mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-14 15:16:35 +03:00
more progress
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"css": {
|
||||
"parser": {
|
||||
"tailwindDirectives": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "vibe-design-plugins",
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4.1.18",
|
||||
},
|
||||
"devDependencies": {
|
||||
"bun-plugin-tailwind": "^0.1.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@oven/bun-darwin-aarch64": ["@oven/bun-darwin-aarch64@1.3.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2Ie4jDGvNGuPSD+pyyBKL8dJmX+bZfDNYEalwgROImVtwB1XYAatJK20dMaRlPA7jOhjvS9Io+4IZAJu7Js0AA=="],
|
||||
|
||||
"@oven/bun-darwin-x64": ["@oven/bun-darwin-x64@1.3.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-4/BJojT8hk5g6Gecjn5yI7y96/+9Mtzsvdp9+2dcy9sTMdlV7jBvDzswqyJPZyQqw0F3HV3Vu9XuMubZwKd9lA=="],
|
||||
|
||||
"@oven/bun-darwin-x64-baseline": ["@oven/bun-darwin-x64-baseline@1.3.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZYxzIOCDqylTMsnWYERjKMMuK2b4an4qbloBmUZTwLHmVzos00yrhtpitZhJBgH6yB/l4Q5eoJ2W98UKtFFeiQ=="],
|
||||
|
||||
"@oven/bun-linux-aarch64": ["@oven/bun-linux-aarch64@1.3.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-8DUIlanftMdFxLGq2FxwKwfrp8O4ZofF/8Oc6lxCyEFmg2hixbHhL04+fPfJIi5D4hZloynxZdwTeDbGv/Kc4A=="],
|
||||
|
||||
"@oven/bun-linux-aarch64-musl": ["@oven/bun-linux-aarch64-musl@1.3.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-6UtmM4wXgRKz+gnLZEfddfsuBSVQpJr09K12e5pbdnLzeWgXYlBT5FG8S7SVn1t6cbgBMnigEsFjWwfTuMNoCw=="],
|
||||
|
||||
"@oven/bun-linux-x64": ["@oven/bun-linux-x64@1.3.4", "", { "os": "linux", "cpu": "x64" }, "sha512-03iSDMqdrmIFAsvsRptq+A7EGNjkg20dNzPnqxAlXHk5rc1PeIRWIP0eIn0i3nI6mmdj33mimf9AGr0+d0lKMg=="],
|
||||
|
||||
"@oven/bun-linux-x64-baseline": ["@oven/bun-linux-x64-baseline@1.3.4", "", { "os": "linux", "cpu": "x64" }, "sha512-ZMGPbFPqmG/VYJv61D+Y1V7T23jPK57vYl7yYLakmkTRjG6vcJ0Akhb2qR1iW94rHvfEBjeuVDAZBp8Qp9oyWA=="],
|
||||
|
||||
"@oven/bun-linux-x64-musl": ["@oven/bun-linux-x64-musl@1.3.4", "", { "os": "linux", "cpu": "x64" }, "sha512-xUXPuJHndGhk4K3Cx1FgTyTgDZOn+ki3eWvdXYqKdfi0EaNA9KpUq+/vUtpJbZRjzpHs9L+OJcdDILq5H0LX4g=="],
|
||||
|
||||
"@oven/bun-linux-x64-musl-baseline": ["@oven/bun-linux-x64-musl-baseline@1.3.4", "", { "os": "linux", "cpu": "x64" }, "sha512-qsGSSlNsxiX8lAayK2uYCfMLtqu776F0nn7qoyzg9Ti7mElM3woNh7RtGClTwQ6qsp5/UvgqT9g4pLaDHmqJFg=="],
|
||||
|
||||
"@oven/bun-windows-x64": ["@oven/bun-windows-x64@1.3.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nswsuN6+HZPim6x4tFpDFpMa/qpTKfywbGvCkzxwrbJO9MtpuW/54NA1nFbHhpV14OLU0xuxyBj2PK4FHq4MlA=="],
|
||||
|
||||
"@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.3.4", "", { "os": "win32", "cpu": "x64" }, "sha512-ZQiSDFfSUdOrPTiL2GvkxlC/kMED4fsJwdZnwJK6S9ylXnk9xY/9ZXfe1615SFLQl2LsVRzJAtjQLeM0BifIKQ=="],
|
||||
|
||||
"bun": ["bun@1.3.4", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.3.4", "@oven/bun-darwin-x64": "1.3.4", "@oven/bun-darwin-x64-baseline": "1.3.4", "@oven/bun-linux-aarch64": "1.3.4", "@oven/bun-linux-aarch64-musl": "1.3.4", "@oven/bun-linux-x64": "1.3.4", "@oven/bun-linux-x64-baseline": "1.3.4", "@oven/bun-linux-x64-musl": "1.3.4", "@oven/bun-linux-x64-musl-baseline": "1.3.4", "@oven/bun-windows-x64": "1.3.4", "@oven/bun-windows-x64-baseline": "1.3.4" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bunx.exe" } }, "sha512-xV6KgD5ImquuKsoghzbWmYzeCXmmSgN6yJGz444hri2W+NGKNRFUNrEhy9+/rRXbvNA2qF0K0jAwqFNy1/GhBg=="],
|
||||
|
||||
"bun-plugin-tailwind": ["bun-plugin-tailwind@0.1.2", "", { "peerDependencies": { "bun": ">=1.0.0" } }, "sha512-41jNC1tZRSK3s1o7pTNrLuQG8kL/0vR/JgiTmZAJ1eHwe0w5j6HFPKeqEk0WAD13jfrUC7+ULuewFBBCoADPpg=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Configure Tailwind CSS plugin for Bun's static server and bundler
|
||||
[serve.static]
|
||||
plugins = ["bun-plugin-tailwind"]
|
||||
+7
-2
@@ -21,6 +21,11 @@
|
||||
"ux"
|
||||
],
|
||||
"author": "Paul Bakaus",
|
||||
"license": "SEE LICENSE FILE"
|
||||
"license": "SEE LICENSE FILE",
|
||||
"devDependencies": {
|
||||
"bun-plugin-tailwind": "^0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4.1.18"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/* Animations & Keyframes */
|
||||
|
||||
/* Background Atmosphere */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 30%, var(--c-accent-dim) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 70%, var(--c-accent-dim) 0%, transparent 50%);
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
animation: fadeInBg var(--duration-slowest) var(--ease-out) 0.3s forwards;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Keyframe Definitions */
|
||||
@keyframes fadeInBg {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-40px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(40px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes expandLine {
|
||||
from {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes drawCircle {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation Utilities */
|
||||
[data-animate] {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
|
||||
&.animated {
|
||||
animation: fadeInUp var(--duration-slow) var(--ease-out) both;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/* Button Components */
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.875rem 2rem;
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-base) var(--ease-out);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Primary Button */
|
||||
.btn-primary {
|
||||
background: var(--c-accent);
|
||||
color: var(--c-paper);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--c-ink);
|
||||
transform: translateY(100%);
|
||||
transition: transform var(--duration-base) var(--ease-out);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Secondary Button */
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: var(--c-ink);
|
||||
border: 1px solid var(--c-ink);
|
||||
|
||||
&:hover {
|
||||
background: var(--c-ink);
|
||||
color: var(--c-paper);
|
||||
}
|
||||
}
|
||||
|
||||
/* Small Button Variant */
|
||||
.btn-small {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8125rem;
|
||||
border: 1px solid var(--c-mist);
|
||||
background: transparent;
|
||||
color: var(--c-ink);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--c-accent);
|
||||
color: var(--c-accent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/* Card Components */
|
||||
|
||||
/* Download Bundles Section */
|
||||
.download-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
gap: var(--s-md);
|
||||
|
||||
@media (max-width: 640px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.download-card {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
|
||||
&.animated {
|
||||
animation: fadeInUp var(--duration-slow) var(--ease-out) both;
|
||||
}
|
||||
}
|
||||
|
||||
.card-inner {
|
||||
height: 100%;
|
||||
padding: var(--s-lg);
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-md);
|
||||
transition: all var(--duration-base) var(--ease-out);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: var(--c-accent);
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.4s var(--ease-out);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--c-accent);
|
||||
transform: translateY(-4px);
|
||||
|
||||
&::before {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: var(--s-md);
|
||||
|
||||
h3 {
|
||||
font-size: 1.375rem;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.625rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
padding: 0.25em 0.625em;
|
||||
border: 1px solid var(--c-accent);
|
||||
color: var(--c-accent);
|
||||
border-radius: 2px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-inner p {
|
||||
color: var(--c-ash);
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.6;
|
||||
flex-grow: 1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Contribute Section */
|
||||
.contribute {
|
||||
padding: var(--s-2xl) 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contribute-content {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.contribute h2 {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: var(--s-sm);
|
||||
}
|
||||
|
||||
.contribute p {
|
||||
font-size: 1.125rem;
|
||||
color: var(--c-ash);
|
||||
margin-bottom: var(--s-lg);
|
||||
line-height: 1.6;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/* Footer & Contribute Section */
|
||||
|
||||
.contribute {
|
||||
padding: var(--s-2xl) 0;
|
||||
border-top: 1px solid var(--c-mist);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contribute-content {
|
||||
max-width: var(--content-width);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--s-md);
|
||||
|
||||
h2 {
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.125rem;
|
||||
color: var(--c-ash);
|
||||
max-width: 42ch;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
border-top: 1px solid var(--c-mist);
|
||||
padding: var(--s-2xl) var(--s-lg);
|
||||
background: var(--c-paper);
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 0.875rem;
|
||||
color: var(--c-ash);
|
||||
|
||||
a {
|
||||
color: var(--c-ink);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
gap: var(--s-sm);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print Styles */
|
||||
@media print {
|
||||
body::before,
|
||||
.hero-decoration,
|
||||
.btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
+72
-72
@@ -10,11 +10,11 @@
|
||||
}
|
||||
|
||||
.skill-nav-item {
|
||||
padding: var(--s-sm) var(--s-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-left: 2px solid transparent;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 400;
|
||||
@@ -26,14 +26,14 @@
|
||||
}
|
||||
|
||||
.skill-nav-item:hover {
|
||||
color: var(--c-text);
|
||||
background: color-mix(in oklch, var(--c-paper) 85%, var(--c-accent));
|
||||
color: var(--color-text);
|
||||
background: color-mix(in oklch, var(--color-paper) 85%, var(--color-accent));
|
||||
}
|
||||
|
||||
.skill-nav-item.active {
|
||||
color: var(--c-accent);
|
||||
border-left-color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, var(--c-paper));
|
||||
color: var(--color-accent);
|
||||
border-left-color: var(--color-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, var(--color-paper));
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -41,17 +41,17 @@
|
||||
.skills-nav {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.skill-nav-item {
|
||||
border-left: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: var(--s-xs) var(--s-md);
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
}
|
||||
|
||||
.skill-nav-item.active {
|
||||
border-bottom-color: var(--c-accent);
|
||||
border-bottom-color: var(--color-accent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
.skills-showcase {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--s-lg);
|
||||
gap: var(--spacing-lg);
|
||||
align-items: start;
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
@@ -86,7 +86,7 @@
|
||||
}
|
||||
|
||||
.skill-header {
|
||||
margin-bottom: var(--s-md);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.skill-header h3 {
|
||||
@@ -94,17 +94,17 @@
|
||||
font-size: 1.75rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
margin: 0 0 var(--s-xs) 0;
|
||||
color: var(--c-text);
|
||||
margin: 0 0 var(--spacing-xs) 0;
|
||||
color: var(--color-text);
|
||||
letter-spacing: -0.02em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.skill-header .meta {
|
||||
display: flex;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
align-items: center;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.03em;
|
||||
@@ -112,7 +112,7 @@
|
||||
}
|
||||
|
||||
.skill-header .meta a {
|
||||
color: var(--c-accent);
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
@@ -124,22 +124,22 @@
|
||||
.skill-description {
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: var(--s-md);
|
||||
color: var(--c-charcoal);
|
||||
margin-bottom: var(--spacing-md);
|
||||
color: var(--color-charcoal);
|
||||
max-width: 50ch;
|
||||
}
|
||||
|
||||
/* Skill Sections (Focus Areas, Relationships) */
|
||||
.skill-section {
|
||||
margin-bottom: var(--s-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.skill-section h4 {
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 var(--s-sm) 0;
|
||||
color: var(--c-ash);
|
||||
margin: 0 0 var(--spacing-sm) 0;
|
||||
color: var(--color-ash);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
@@ -148,26 +148,26 @@
|
||||
.focus-areas-compact {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.focus-area-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--s-xs);
|
||||
padding: var(--s-xs) var(--s-sm);
|
||||
background: var(--c-paper);
|
||||
gap: var(--spacing-xs);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
background: var(--color-paper);
|
||||
border-radius: 3px;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.focus-area-tag strong {
|
||||
color: var(--c-text);
|
||||
color: var(--color-text);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.focus-area-tag span {
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -175,15 +175,15 @@
|
||||
.relationship-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.relationship-tag {
|
||||
display: inline-block;
|
||||
padding: var(--s-xs) var(--s-sm);
|
||||
background: var(--c-paper);
|
||||
color: var(--c-text);
|
||||
border: 1px solid color-mix(in oklch, var(--c-accent) 30%, transparent);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
background: var(--color-paper);
|
||||
color: var(--color-text);
|
||||
border: 1px solid color-mix(in oklch, var(--color-accent) 30%, transparent);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 400;
|
||||
border-radius: 2px;
|
||||
@@ -192,36 +192,36 @@
|
||||
}
|
||||
|
||||
.relationship-tag:hover {
|
||||
border-color: var(--c-accent);
|
||||
color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, var(--c-paper));
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, var(--color-paper));
|
||||
}
|
||||
|
||||
/* Skill Downloads (Icons) */
|
||||
.skill-downloads {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
padding-top: var(--s-md);
|
||||
margin-top: var(--s-md);
|
||||
border-top: 1px solid var(--c-mist);
|
||||
gap: var(--spacing-sm);
|
||||
padding-top: var(--spacing-md);
|
||||
margin-top: var(--spacing-md);
|
||||
border-top: 1px solid var(--color-mist);
|
||||
}
|
||||
|
||||
.downloads-label {
|
||||
font-size: 0.75rem;
|
||||
color: var(--c-ash);
|
||||
margin-right: var(--s-xs);
|
||||
color: var(--color-ash);
|
||||
margin-right: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.download-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-xs);
|
||||
gap: var(--spacing-xs);
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
border: 1px solid var(--c-mist);
|
||||
color: var(--c-ash);
|
||||
border: 1px solid var(--color-mist);
|
||||
color: var(--color-ash);
|
||||
text-decoration: none;
|
||||
font-size: 0.75rem;
|
||||
transition: all 0.15s ease;
|
||||
@@ -234,16 +234,16 @@
|
||||
}
|
||||
|
||||
.download-icon:hover {
|
||||
color: var(--c-accent);
|
||||
border-color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, transparent);
|
||||
color: var(--color-accent);
|
||||
border-color: var(--color-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, transparent);
|
||||
}
|
||||
|
||||
/* Command Detail Panel - mirrors skills showcase */
|
||||
.command-detail-panel {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 1fr;
|
||||
gap: var(--s-lg);
|
||||
gap: var(--spacing-lg);
|
||||
align-items: start;
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
@@ -263,15 +263,15 @@
|
||||
font-family: 'Space Grotesk', monospace;
|
||||
font-size: 2rem;
|
||||
font-weight: 500;
|
||||
margin: 0 0 var(--s-xs) 0;
|
||||
color: var(--c-text);
|
||||
margin: 0 0 var(--spacing-xs) 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.command-header .meta {
|
||||
display: flex;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
align-items: center;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-size: 0.8125rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
@@ -280,24 +280,24 @@
|
||||
.command-description {
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
color: var(--c-charcoal);
|
||||
margin-bottom: var(--s-lg);
|
||||
color: var(--color-charcoal);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* Process Steps - Compact */
|
||||
.process-steps-compact {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
counter-reset: step;
|
||||
}
|
||||
|
||||
.process-step-compact {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-xs);
|
||||
padding: var(--s-xs) var(--s-sm);
|
||||
background: var(--c-paper);
|
||||
gap: var(--spacing-xs);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
background: var(--color-paper);
|
||||
border-radius: 3px;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
@@ -310,8 +310,8 @@
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: var(--c-accent);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-accent);
|
||||
color: var(--color-paper);
|
||||
border-radius: 50%;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
@@ -331,10 +331,10 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 2px 5px;
|
||||
background: var(--c-mist);
|
||||
color: var(--c-ash);
|
||||
background: var(--color-mist);
|
||||
color: var(--color-ash);
|
||||
border-radius: 2px;
|
||||
margin-left: var(--s-xs);
|
||||
margin-left: var(--spacing-xs);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -344,13 +344,13 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
padding: var(--s-2xl);
|
||||
padding: var(--spacing-2xl);
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.coming-soon-icon {
|
||||
color: var(--c-mist);
|
||||
margin-bottom: var(--s-lg);
|
||||
color: var(--color-mist);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.coming-soon-showcase h3 {
|
||||
@@ -358,20 +358,20 @@
|
||||
font-size: 1.75rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
margin: 0 0 var(--s-sm) 0;
|
||||
color: var(--c-text);
|
||||
margin: 0 0 var(--spacing-sm) 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.coming-soon-text {
|
||||
font-size: 1rem;
|
||||
color: var(--c-accent);
|
||||
color: var(--color-accent);
|
||||
font-weight: 500;
|
||||
margin-bottom: var(--s-md);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.coming-soon-showcase .skill-description {
|
||||
max-width: 50ch;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/* Hero Section */
|
||||
|
||||
.hero {
|
||||
min-height: 85vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: var(--s-2xl) var(--s-lg);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
gap: var(--s-2xl);
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
animation: slideInLeft var(--duration-slower) var(--ease-out) 0.1s both;
|
||||
}
|
||||
|
||||
/* Title Styling */
|
||||
.title {
|
||||
font-size: clamp(3rem, 8vw, 7rem);
|
||||
font-weight: 300;
|
||||
line-height: 0.9;
|
||||
margin-bottom: var(--s-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: -0.1em;
|
||||
}
|
||||
|
||||
.title-main {
|
||||
font-weight: 400;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.title-sub {
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
color: var(--c-accent);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
/* Tagline & Providers */
|
||||
.tagline {
|
||||
font-size: clamp(1.125rem, 2vw, 1.5rem);
|
||||
line-height: 1.4;
|
||||
color: var(--c-charcoal);
|
||||
margin-bottom: var(--s-md);
|
||||
max-width: 32ch;
|
||||
}
|
||||
|
||||
.providers {
|
||||
font-size: 0.875rem;
|
||||
color: var(--c-ash);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Decorative Elements */
|
||||
.hero-decoration {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
position: relative;
|
||||
animation: slideInRight var(--duration-slower) var(--ease-out) 0.3s both;
|
||||
}
|
||||
|
||||
.deco-line {
|
||||
position: absolute;
|
||||
width: 160px;
|
||||
height: 2px;
|
||||
background: var(--c-accent);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) rotate(-25deg);
|
||||
animation: expandLine 1s var(--ease-out) 0.6s both;
|
||||
}
|
||||
|
||||
.deco-circle {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 2px solid var(--c-accent);
|
||||
border-radius: 50%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: drawCircle 1s var(--ease-out) 0.8s both;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Hero Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.hero {
|
||||
min-height: 70vh;
|
||||
padding: var(--s-xl) var(--s-md);
|
||||
}
|
||||
|
||||
.hero-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--s-xl);
|
||||
}
|
||||
|
||||
.hero-decoration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: clamp(2.5rem, 12vw, 4rem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/* Intro Section */
|
||||
|
||||
.intro {
|
||||
padding: var(--s-2xl) 0;
|
||||
}
|
||||
|
||||
.intro-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr;
|
||||
gap: var(--s-2xl);
|
||||
align-items: start;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--s-xl);
|
||||
}
|
||||
}
|
||||
|
||||
.intro-content h2 {
|
||||
font-size: clamp(1.75rem, 3vw, 2.5rem);
|
||||
font-weight: 400;
|
||||
line-height: 1.3;
|
||||
color: var(--c-charcoal);
|
||||
}
|
||||
|
||||
/* Meta Statistics */
|
||||
.intro-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-lg);
|
||||
padding-top: var(--s-md);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-xs);
|
||||
}
|
||||
|
||||
.meta-number {
|
||||
font-family: var(--font-display);
|
||||
font-size: 3rem;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
color: var(--c-accent);
|
||||
|
||||
@media (max-width: 480px) {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-ash);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/* Layout Components */
|
||||
|
||||
.container {
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--s-lg);
|
||||
|
||||
@media (max-width: 640px) {
|
||||
padding: 0 var(--s-md);
|
||||
}
|
||||
}
|
||||
|
||||
/* Section Styling */
|
||||
section {
|
||||
border-top: 1px solid var(--c-mist);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
font-weight: 600;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: var(--s-sm);
|
||||
position: relative;
|
||||
display: block;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -0.25em;
|
||||
left: 0;
|
||||
width: 80px;
|
||||
height: 2px;
|
||||
background: var(--c-accent);
|
||||
}
|
||||
|
||||
@media (max-width: 968px) {
|
||||
margin-bottom: var(--s-lg);
|
||||
}
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1.125rem;
|
||||
color: var(--c-ash);
|
||||
margin-top: var(--s-md);
|
||||
max-width: 50ch;
|
||||
}
|
||||
|
||||
/* Section Headers */
|
||||
.section-header-sticky {
|
||||
margin-bottom: var(--s-lg);
|
||||
|
||||
.section-title {
|
||||
margin-bottom: var(--s-sm);
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
margin-top: var(--s-sm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Skills Section Layout */
|
||||
.skills-section {
|
||||
padding: var(--s-xl) 0;
|
||||
}
|
||||
|
||||
.skills-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 180px 1fr;
|
||||
gap: var(--s-lg);
|
||||
align-items: start;
|
||||
|
||||
@media (max-width: 968px) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--s-md);
|
||||
}
|
||||
}
|
||||
|
||||
.skills-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
@media (max-width: 968px) {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.skills-showcase {
|
||||
/* Contain the showcase to prevent excessive scrolling */
|
||||
}
|
||||
|
||||
/* Commands Section Layout - mirrors skills layout */
|
||||
.commands-section {
|
||||
padding: var(--s-xl) 0;
|
||||
}
|
||||
|
||||
.commands-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 180px 1fr;
|
||||
gap: var(--s-lg);
|
||||
align-items: start;
|
||||
|
||||
@media (max-width: 968px) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--s-md);
|
||||
}
|
||||
}
|
||||
|
||||
.commands-nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-sm);
|
||||
|
||||
@media (max-width: 968px) {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.commands-showcase {
|
||||
/* Contains demo + info */
|
||||
}
|
||||
|
||||
/* Downloads Section */
|
||||
.downloads-section {
|
||||
padding: var(--s-2xl) 0;
|
||||
}
|
||||
|
||||
.downloads-header {
|
||||
margin-bottom: var(--s-xl);
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.downloads-header .section-title {
|
||||
margin-bottom: var(--s-md);
|
||||
}
|
||||
|
||||
.downloads-lead {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.6;
|
||||
color: var(--c-ash);
|
||||
}
|
||||
|
||||
/* Grid Utilities */
|
||||
.item-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: var(--s-md);
|
||||
}
|
||||
|
||||
/* Loading State */
|
||||
.loading {
|
||||
padding: var(--s-xl);
|
||||
text-align: center;
|
||||
color: var(--c-ash);
|
||||
font-style: italic;
|
||||
}
|
||||
+370
-22
@@ -1,29 +1,377 @@
|
||||
/*
|
||||
* impeccable.style — Modular CSS Architecture
|
||||
* impeccable.style — Tailwind CSS v4 + Custom Components
|
||||
*
|
||||
* Uses Bun's CSS bundler for:
|
||||
* - CSS nesting (no preprocessor needed)
|
||||
* - OKLCH colors with automatic fallbacks
|
||||
* - Automatic bundling via @import
|
||||
*
|
||||
* Structure:
|
||||
* - tokens.css: Design system (colors, spacing, typography)
|
||||
* - reset.css: Modern baseline
|
||||
* - animations.css: Keyframes & utilities
|
||||
* - layout.css: Grid & section primitives
|
||||
* - hero/intro/buttons/cards/footer.css: Component styles
|
||||
* Architecture:
|
||||
* - Tailwind v4 with custom theme tokens
|
||||
* - Custom components for complex UI patterns
|
||||
* - Minimal CSS for what Tailwind can't express
|
||||
*/
|
||||
|
||||
@import "./tokens.css";
|
||||
@import "./reset.css";
|
||||
@import "./animations.css";
|
||||
@import "./layout.css";
|
||||
@import "./hero.css";
|
||||
@import "./buttons.css";
|
||||
@import "./cards.css";
|
||||
@import "./gallery.css";
|
||||
@import "tailwindcss";
|
||||
|
||||
/* ============================================
|
||||
TAILWIND THEME - Static Design Tokens
|
||||
============================================ */
|
||||
|
||||
@theme {
|
||||
/* Typography */
|
||||
--font-display: 'Cormorant Garamond', Georgia, serif;
|
||||
--font-body: 'Instrument Sans', system-ui, sans-serif;
|
||||
--font-mono: 'Space Grotesk', monospace;
|
||||
|
||||
/* Spacing Scale */
|
||||
--spacing-xs: 8px;
|
||||
--spacing-sm: 16px;
|
||||
--spacing-md: 24px;
|
||||
--spacing-lg: 48px;
|
||||
--spacing-xl: 80px;
|
||||
--spacing-2xl: 128px;
|
||||
--spacing-3xl: 192px;
|
||||
|
||||
/* Width */
|
||||
--width-max: 1280px;
|
||||
--width-content: 840px;
|
||||
|
||||
/* Animation */
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--duration-fast: 0.2s;
|
||||
--duration-base: 0.3s;
|
||||
--duration-slow: 0.6s;
|
||||
--duration-slower: 0.8s;
|
||||
--duration-slowest: 1.2s;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
COLOR TOKENS - Light/Dark Mode via CSS
|
||||
============================================ */
|
||||
|
||||
:root {
|
||||
/* Colors - Light Mode */
|
||||
--color-ink: oklch(10% 0 0);
|
||||
--color-text: oklch(10% 0 0);
|
||||
--color-paper: oklch(98% 0 0);
|
||||
--color-charcoal: oklch(25% 0 0);
|
||||
--color-ash: oklch(55% 0 0);
|
||||
--color-mist: oklch(92% 0 0);
|
||||
--color-bg: oklch(96% 0.005 350);
|
||||
--color-accent: oklch(60% 0.25 350);
|
||||
--color-accent-hover: oklch(52% 0.25 350);
|
||||
--color-accent-dim: oklch(60% 0.25 350 / 0.15);
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-ink: oklch(98% 0 0);
|
||||
--color-text: oklch(98% 0 0);
|
||||
--color-paper: oklch(10% 0 0);
|
||||
--color-charcoal: oklch(92% 0 0);
|
||||
--color-ash: oklch(65% 0 0);
|
||||
--color-mist: oklch(20% 0 0);
|
||||
--color-bg: oklch(12% 0.005 350);
|
||||
--color-accent: oklch(68% 0.23 350);
|
||||
--color-accent-hover: oklch(76% 0.23 350);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
BASE STYLES
|
||||
============================================ */
|
||||
|
||||
html {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
color: var(--color-ink);
|
||||
background: var(--color-paper);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 600;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
transition: opacity var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
SECTION TITLE - With accent underline
|
||||
============================================ */
|
||||
|
||||
.section-title {
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
font-weight: 600;
|
||||
position: relative;
|
||||
display: block;
|
||||
padding-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.section-title::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -0.25em;
|
||||
left: 0;
|
||||
width: 80px;
|
||||
height: 2px;
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
BACKGROUND ATMOSPHERE
|
||||
============================================ */
|
||||
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 30%, var(--color-accent-dim) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 70%, var(--color-accent-dim) 0%, transparent 50%);
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
animation: fadeInBg var(--duration-slowest) var(--ease-out) 0.3s forwards;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
HERO DECORATIONS
|
||||
============================================ */
|
||||
|
||||
.deco-line {
|
||||
position: absolute;
|
||||
width: 160px;
|
||||
height: 2px;
|
||||
background: var(--color-accent);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) rotate(-25deg);
|
||||
animation: expandLine 1s var(--ease-out) 0.6s both;
|
||||
}
|
||||
|
||||
.deco-circle {
|
||||
position: absolute;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border: 2px solid var(--color-accent);
|
||||
border-radius: 50%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: drawCircle 1s var(--ease-out) 0.8s both;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
BUTTONS
|
||||
============================================ */
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.875rem 2rem;
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-base) var(--ease-out);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--color-accent);
|
||||
color: var(--color-paper);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.btn-primary::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: var(--color-ink);
|
||||
transform: translateY(100%);
|
||||
transition: transform var(--duration-base) var(--ease-out);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.btn-primary:hover::before {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: transparent;
|
||||
color: var(--color-ink);
|
||||
border: 1px solid var(--color-ink);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--color-ink);
|
||||
color: var(--color-paper);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
CARD COMPONENTS
|
||||
============================================ */
|
||||
|
||||
.card-inner {
|
||||
height: 100%;
|
||||
padding: var(--spacing-lg);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-md);
|
||||
transition: all var(--duration-base) var(--ease-out);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-inner::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: var(--color-accent);
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.4s var(--ease-out);
|
||||
}
|
||||
|
||||
.card-inner:hover {
|
||||
border-color: var(--color-accent);
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.card-inner:hover::before {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.625rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
padding: 0.25em 0.625em;
|
||||
border: 1px solid var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
border-radius: 2px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
SOLUTION CARDS
|
||||
============================================ */
|
||||
|
||||
.solution-card {
|
||||
padding: var(--spacing-lg);
|
||||
background: var(--color-paper);
|
||||
border-left: 3px solid var(--color-accent);
|
||||
transition: all var(--duration-base) var(--ease-out);
|
||||
}
|
||||
|
||||
.solution-card:hover {
|
||||
background: color-mix(in oklch, var(--color-paper) 90%, var(--color-accent));
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.solution-card code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.875em;
|
||||
background: color-mix(in oklch, var(--color-accent) 15%, transparent);
|
||||
color: var(--color-accent);
|
||||
padding: 0.125em 0.375em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ANIMATIONS
|
||||
============================================ */
|
||||
|
||||
@keyframes fadeInBg {
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-40px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(40px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes expandLine {
|
||||
from { width: 0; }
|
||||
}
|
||||
|
||||
@keyframes drawCircle {
|
||||
from {
|
||||
opacity: 0;
|
||||
scale: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
scale: 1;
|
||||
}
|
||||
}
|
||||
|
||||
[data-animate] {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
[data-animate].animated {
|
||||
animation: fadeInUp var(--duration-slow) var(--ease-out) both;
|
||||
}
|
||||
|
||||
/* Hero animations */
|
||||
.hero-content {
|
||||
animation: slideInLeft var(--duration-slower) var(--ease-out) 0.1s both;
|
||||
}
|
||||
|
||||
.hero-decoration {
|
||||
animation: slideInRight var(--duration-slower) var(--ease-out) 0.3s both;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
IMPORTS - Complex components that need custom CSS
|
||||
============================================ */
|
||||
|
||||
@import "./problem-section.css";
|
||||
@import "./solution-section.css";
|
||||
@import "./skill-demos.css";
|
||||
@import "./gallery.css";
|
||||
@import "./workflow.css";
|
||||
@import "./footer.css";
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
*/
|
||||
|
||||
.problem-section {
|
||||
padding: var(--s-2xl) 0;
|
||||
border-top: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-2xl) 0;
|
||||
border-top: 1px solid var(--color-mist);
|
||||
}
|
||||
|
||||
.problem-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--s-2xl);
|
||||
gap: var(--spacing-2xl);
|
||||
align-items: center;
|
||||
|
||||
@media (max-width: 968px) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--s-xl);
|
||||
gap: var(--spacing-xl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
}
|
||||
|
||||
.problem-content .section-title {
|
||||
margin-bottom: var(--s-md);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.problem-lead {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.6;
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
}
|
||||
|
||||
/* AI Slop Demo - Deliberately generic design */
|
||||
@@ -124,10 +124,10 @@
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-accent);
|
||||
background: var(--c-paper);
|
||||
color: var(--color-accent);
|
||||
background: var(--color-paper);
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--c-accent);
|
||||
border: 1px solid var(--color-accent);
|
||||
border-radius: 2px;
|
||||
white-space: nowrap;
|
||||
opacity: 0;
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/* Modern CSS Reset */
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 16px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--c-ink);
|
||||
background: var(--c-paper);
|
||||
overflow-x: hidden;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Typography Defaults */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 600;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
p {
|
||||
max-width: 65ch;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--c-accent);
|
||||
text-decoration: none;
|
||||
transition: opacity var(--duration-fast) var(--ease-out);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/* Better image defaults */
|
||||
img,
|
||||
picture,
|
||||
video,
|
||||
canvas,
|
||||
svg {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Remove default button styles */
|
||||
button {
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
+175
-175
@@ -14,30 +14,30 @@
|
||||
.demo-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
margin-bottom: var(--s-sm);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.demo-tab {
|
||||
padding: var(--s-xs) var(--s-md);
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 400;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.demo-tab:hover {
|
||||
color: var(--c-text);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.demo-tab.active {
|
||||
color: var(--c-accent);
|
||||
border-bottom-color: var(--c-accent);
|
||||
color: var(--color-accent);
|
||||
border-bottom-color: var(--color-accent);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@
|
||||
============================================ */
|
||||
|
||||
.demo-container {
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -68,16 +68,16 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding: var(--s-xs) var(--s-md);
|
||||
background: var(--c-bg);
|
||||
border-bottom: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
background: var(--color-bg);
|
||||
border-bottom: 1px solid var(--color-mist);
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.demo-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.demo-toggle-label {
|
||||
@@ -85,19 +85,19 @@
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.demo-toggle-label.active {
|
||||
color: var(--c-accent);
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.demo-toggle-switch {
|
||||
position: relative;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
background: var(--c-mist);
|
||||
background: var(--color-mist);
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease;
|
||||
@@ -110,14 +110,14 @@
|
||||
left: 2px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--c-paper);
|
||||
background: var(--color-paper);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
|
||||
.demo-toggle-switch.active {
|
||||
background: var(--c-accent);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
.demo-toggle-switch.active::after {
|
||||
@@ -125,20 +125,20 @@
|
||||
}
|
||||
|
||||
.demo-viewport {
|
||||
padding: var(--s-lg);
|
||||
padding: var(--spacing-lg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 200px;
|
||||
background: var(--c-bg);
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
.demo-caption {
|
||||
padding: var(--s-xs) var(--s-md);
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
font-size: 0.75rem;
|
||||
color: var(--c-ash);
|
||||
border-top: 1px solid var(--c-mist);
|
||||
background: var(--c-bg);
|
||||
color: var(--color-ash);
|
||||
border-top: 1px solid var(--color-mist);
|
||||
background: var(--color-bg);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -149,39 +149,39 @@
|
||||
.uxw-demo {
|
||||
width: 100%;
|
||||
max-width: 320px;
|
||||
padding: var(--s-lg);
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-lg);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Error Messages */
|
||||
.uxw-error-icon { font-size: 2rem; margin-bottom: var(--s-sm); }
|
||||
.uxw-error-title { font-weight: 600; color: #c00; margin-bottom: var(--s-xs); }
|
||||
.uxw-error-text { font-size: 0.875rem; color: var(--c-ash); }
|
||||
.uxw-error-action { margin-top: var(--s-sm); font-size: 0.875rem; color: var(--c-accent); cursor: pointer; text-decoration: underline; }
|
||||
.uxw-error-icon { font-size: 2rem; margin-bottom: var(--spacing-sm); }
|
||||
.uxw-error-title { font-weight: 600; color: #c00; margin-bottom: var(--spacing-xs); }
|
||||
.uxw-error-text { font-size: 0.875rem; color: var(--color-ash); }
|
||||
.uxw-error-action { margin-top: var(--spacing-sm); font-size: 0.875rem; color: var(--color-accent); cursor: pointer; text-decoration: underline; }
|
||||
|
||||
.uxw-error-after .uxw-error-icon { color: var(--c-accent); }
|
||||
.uxw-error-after .uxw-error-title { color: var(--c-text); }
|
||||
.uxw-error-after .uxw-error-text { color: var(--c-charcoal); }
|
||||
.uxw-error-after .uxw-error-icon { color: var(--color-accent); }
|
||||
.uxw-error-after .uxw-error-title { color: var(--color-text); }
|
||||
.uxw-error-after .uxw-error-text { color: var(--color-charcoal); }
|
||||
|
||||
/* Button Labels */
|
||||
.uxw-button-context { font-size: 0.875rem; color: var(--c-charcoal); margin-bottom: var(--s-md); font-weight: 500; }
|
||||
.uxw-button-row { display: flex; gap: var(--s-sm); justify-content: center; }
|
||||
.uxw-btn { padding: var(--s-xs) var(--s-md); border-radius: 4px; font-size: 0.875rem; font-weight: 500; cursor: pointer; border: none; }
|
||||
.uxw-btn-primary { background: var(--c-text); color: var(--c-paper); }
|
||||
.uxw-btn-secondary { background: transparent; color: var(--c-ash); border: 1px solid var(--c-mist); }
|
||||
.uxw-button-context { font-size: 0.875rem; color: var(--color-charcoal); margin-bottom: var(--spacing-md); font-weight: 500; }
|
||||
.uxw-button-row { display: flex; gap: var(--spacing-sm); justify-content: center; }
|
||||
.uxw-btn { padding: var(--spacing-xs) var(--spacing-md); border-radius: 4px; font-size: 0.875rem; font-weight: 500; cursor: pointer; border: none; }
|
||||
.uxw-btn-primary { background: var(--color-text); color: var(--color-paper); }
|
||||
.uxw-btn-secondary { background: transparent; color: var(--color-ash); border: 1px solid var(--color-mist); }
|
||||
.uxw-btn-danger { background: #c00; color: white; }
|
||||
|
||||
/* Empty States */
|
||||
.uxw-empty-icon { font-size: 2.5rem; margin-bottom: var(--s-sm); opacity: 0.4; }
|
||||
.uxw-empty-title { font-weight: 500; color: var(--c-ash); }
|
||||
.uxw-empty-text { font-size: 0.875rem; color: var(--c-charcoal); margin-top: var(--s-xs); }
|
||||
.uxw-empty-action { margin-top: var(--s-md); }
|
||||
.uxw-empty-icon { font-size: 2.5rem; margin-bottom: var(--spacing-sm); opacity: 0.4; }
|
||||
.uxw-empty-title { font-weight: 500; color: var(--color-ash); }
|
||||
.uxw-empty-text { font-size: 0.875rem; color: var(--color-charcoal); margin-top: var(--spacing-xs); }
|
||||
.uxw-empty-action { margin-top: var(--spacing-md); }
|
||||
|
||||
.uxw-empty-after .uxw-empty-icon { opacity: 1; }
|
||||
.uxw-empty-after .uxw-empty-title { color: var(--c-text); }
|
||||
.uxw-empty-after .uxw-empty-title { color: var(--color-text); }
|
||||
|
||||
/* ============================================
|
||||
SPATIAL DESIGN DEMOS
|
||||
@@ -190,9 +190,9 @@
|
||||
.spatial-demo {
|
||||
width: 100%;
|
||||
max-width: 340px;
|
||||
padding: var(--s-md);
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-md);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@@ -206,16 +206,16 @@
|
||||
.spatial-grid-after {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.spatial-card-item {
|
||||
padding: var(--s-sm);
|
||||
background: var(--c-bg);
|
||||
border: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-sm);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 4px;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -229,8 +229,8 @@
|
||||
.spatial-hierarchy-before .spatial-h-cta,
|
||||
.spatial-hierarchy-before .spatial-h-link {
|
||||
font-size: 0.9375rem;
|
||||
margin-bottom: var(--s-xs);
|
||||
color: var(--c-charcoal);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
color: var(--color-charcoal);
|
||||
}
|
||||
|
||||
.spatial-hierarchy-after .spatial-h-title {
|
||||
@@ -238,52 +238,52 @@
|
||||
font-size: 1.75rem;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
margin-bottom: var(--s-xs);
|
||||
color: var(--c-text);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.spatial-hierarchy-after .spatial-h-subtitle {
|
||||
font-size: 0.6875rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--c-ash);
|
||||
margin-bottom: var(--s-md);
|
||||
color: var(--color-ash);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.spatial-hierarchy-after .spatial-h-cta {
|
||||
display: inline-block;
|
||||
padding: var(--s-sm) var(--s-lg);
|
||||
background: var(--c-text);
|
||||
color: var(--c-paper);
|
||||
padding: var(--spacing-sm) var(--spacing-lg);
|
||||
background: var(--color-text);
|
||||
color: var(--color-paper);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
border-radius: 4px;
|
||||
margin-bottom: var(--s-sm);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.spatial-hierarchy-after .spatial-h-link {
|
||||
font-size: 0.75rem;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
}
|
||||
|
||||
/* Whitespace */
|
||||
.spatial-whitespace-before {
|
||||
padding: var(--s-xs) !important;
|
||||
padding: var(--spacing-xs) !important;
|
||||
}
|
||||
|
||||
.spatial-whitespace-before .spatial-ws-title { font-size: 1rem; font-weight: 600; margin-bottom: 2px; }
|
||||
.spatial-whitespace-before .spatial-ws-price { font-size: 0.875rem; color: var(--c-ash); margin-bottom: 4px; }
|
||||
.spatial-whitespace-before .spatial-ws-features { font-size: 0.75rem; color: var(--c-ash); margin-bottom: 6px; }
|
||||
.spatial-whitespace-before .spatial-ws-btn { width: 100%; padding: 6px; font-size: 0.75rem; background: var(--c-text); color: var(--c-paper); border: none; border-radius: 3px; cursor: pointer; }
|
||||
.spatial-whitespace-before .spatial-ws-price { font-size: 0.875rem; color: var(--color-ash); margin-bottom: 4px; }
|
||||
.spatial-whitespace-before .spatial-ws-features { font-size: 0.75rem; color: var(--color-ash); margin-bottom: 6px; }
|
||||
.spatial-whitespace-before .spatial-ws-btn { width: 100%; padding: 6px; font-size: 0.75rem; background: var(--color-text); color: var(--color-paper); border: none; border-radius: 3px; cursor: pointer; }
|
||||
|
||||
.spatial-whitespace-after {
|
||||
padding: var(--s-lg) !important;
|
||||
padding: var(--spacing-lg) !important;
|
||||
}
|
||||
|
||||
.spatial-whitespace-after .spatial-ws-title { font-family: var(--font-display); font-size: 1.5rem; font-weight: 400; margin-bottom: var(--s-sm); }
|
||||
.spatial-whitespace-after .spatial-ws-price { font-size: 1.25rem; font-weight: 600; color: var(--c-text); margin-bottom: var(--s-sm); }
|
||||
.spatial-whitespace-after .spatial-ws-features { font-size: 0.8125rem; color: var(--c-ash); margin-bottom: var(--s-lg); line-height: 1.6; }
|
||||
.spatial-whitespace-after .spatial-ws-btn { width: 100%; padding: var(--s-sm); font-size: 0.875rem; background: var(--c-text); color: var(--c-paper); border: none; border-radius: 4px; cursor: pointer; font-weight: 500; }
|
||||
.spatial-whitespace-after .spatial-ws-title { font-family: var(--font-display); font-size: 1.5rem; font-weight: 400; margin-bottom: var(--spacing-sm); }
|
||||
.spatial-whitespace-after .spatial-ws-price { font-size: 1.25rem; font-weight: 600; color: var(--color-text); margin-bottom: var(--spacing-sm); }
|
||||
.spatial-whitespace-after .spatial-ws-features { font-size: 0.8125rem; color: var(--color-ash); margin-bottom: var(--spacing-lg); line-height: 1.6; }
|
||||
.spatial-whitespace-after .spatial-ws-btn { width: 100%; padding: var(--spacing-sm); font-size: 0.875rem; background: var(--color-text); color: var(--color-paper); border: none; border-radius: 4px; cursor: pointer; font-weight: 500; }
|
||||
|
||||
/* ============================================
|
||||
MOTION DESIGN DEMOS
|
||||
@@ -293,7 +293,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
}
|
||||
@@ -306,19 +306,19 @@
|
||||
.motion-list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
padding: var(--s-sm) var(--s-md);
|
||||
background: var(--c-bg);
|
||||
border: 1px solid var(--c-mist);
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
}
|
||||
|
||||
.motion-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: var(--c-accent);
|
||||
background: var(--color-accent);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
@@ -348,13 +348,13 @@
|
||||
}
|
||||
|
||||
.motion-btn-before {
|
||||
background: var(--c-charcoal);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-charcoal);
|
||||
color: var(--color-paper);
|
||||
}
|
||||
|
||||
.motion-btn-after {
|
||||
background: var(--c-text);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-text);
|
||||
color: var(--color-paper);
|
||||
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
@@ -369,24 +369,24 @@
|
||||
|
||||
/* State Transitions */
|
||||
.motion-card {
|
||||
padding: var(--s-md);
|
||||
background: var(--c-bg);
|
||||
border: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-md);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.motion-card-icon { font-size: 1.5rem; margin-bottom: var(--s-xs); }
|
||||
.motion-card-text { font-size: 0.8125rem; color: var(--c-charcoal); }
|
||||
.motion-card-icon { font-size: 1.5rem; margin-bottom: var(--spacing-xs); }
|
||||
.motion-card-text { font-size: 0.8125rem; color: var(--color-charcoal); }
|
||||
|
||||
.motion-card-after {
|
||||
transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.demo-viewport[data-state="after"] .motion-card-after {
|
||||
background: color-mix(in oklch, var(--c-accent) 10%, var(--c-paper));
|
||||
border-color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 10%, var(--color-paper));
|
||||
border-color: var(--color-accent);
|
||||
}
|
||||
|
||||
.demo-viewport[data-state="after"] .motion-card-after .motion-card-icon {
|
||||
@@ -415,13 +415,13 @@
|
||||
.typo-pairing-before .typo-heading {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: var(--s-xs);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.typo-pairing-before .typo-body {
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.5;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
}
|
||||
|
||||
.typo-pairing-after .typo-heading {
|
||||
@@ -430,21 +430,21 @@
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: var(--s-sm);
|
||||
color: var(--c-text);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.typo-pairing-after .typo-body {
|
||||
font-family: var(--font-body);
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.7;
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
}
|
||||
|
||||
/* Hierarchy */
|
||||
.typo-hierarchy-before .typo-h1 { font-size: 1.125rem; font-weight: 600; margin-bottom: 4px; }
|
||||
.typo-hierarchy-before .typo-meta { font-size: 0.9375rem; color: var(--c-ash); margin-bottom: var(--s-xs); }
|
||||
.typo-hierarchy-before .typo-p { font-size: 0.875rem; line-height: 1.5; color: var(--c-charcoal); }
|
||||
.typo-hierarchy-before .typo-meta { font-size: 0.9375rem; color: var(--color-ash); margin-bottom: var(--spacing-xs); }
|
||||
.typo-hierarchy-before .typo-p { font-size: 0.875rem; line-height: 1.5; color: var(--color-charcoal); }
|
||||
|
||||
.typo-hierarchy-after .typo-h1 {
|
||||
font-family: var(--font-display);
|
||||
@@ -459,14 +459,14 @@
|
||||
font-size: 0.6875rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.12em;
|
||||
color: var(--c-accent);
|
||||
margin-bottom: var(--s-md);
|
||||
color: var(--color-accent);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.typo-hierarchy-after .typo-p {
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.7;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@@ -476,33 +476,33 @@
|
||||
.int-demo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
width: 100%;
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
/* Button States */
|
||||
.int-states-demo {
|
||||
gap: var(--s-lg);
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.int-state-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.int-state-label {
|
||||
font-size: 0.6875rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.int-btn {
|
||||
flex: 1;
|
||||
padding: var(--s-sm) var(--s-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
border-radius: 4px;
|
||||
@@ -510,26 +510,26 @@
|
||||
}
|
||||
|
||||
.int-btn-poor {
|
||||
background: var(--c-charcoal);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-charcoal);
|
||||
color: var(--color-paper);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.int-btn-good {
|
||||
background: var(--c-text);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-text);
|
||||
color: var(--color-paper);
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.int-btn-good:hover {
|
||||
background: var(--c-charcoal);
|
||||
background: var(--color-charcoal);
|
||||
}
|
||||
|
||||
.int-btn-good:focus {
|
||||
outline: none;
|
||||
border-color: var(--c-accent);
|
||||
box-shadow: 0 0 0 3px color-mix(in oklch, var(--c-accent) 25%, transparent);
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-accent) 25%, transparent);
|
||||
}
|
||||
|
||||
.int-btn-good:active {
|
||||
@@ -538,18 +538,18 @@
|
||||
|
||||
/* Affordances */
|
||||
.int-aff-item {
|
||||
padding: var(--s-sm) var(--s-md);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.int-aff-poor {
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
}
|
||||
|
||||
.int-aff-good {
|
||||
color: var(--c-accent);
|
||||
color: var(--color-accent);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
@@ -559,16 +559,16 @@
|
||||
}
|
||||
|
||||
.int-affordance-after .int-aff-item {
|
||||
background: var(--c-bg);
|
||||
border: 1px solid var(--c-mist);
|
||||
color: var(--c-accent);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-mist);
|
||||
color: var(--color-accent);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.int-affordance-after .int-aff-item:hover {
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, var(--c-paper));
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, var(--color-paper));
|
||||
}
|
||||
|
||||
.int-affordance-after .int-aff-item::after {
|
||||
@@ -580,7 +580,7 @@
|
||||
.int-feedback-after {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
@@ -601,13 +601,13 @@
|
||||
}
|
||||
|
||||
.int-fb-silent {
|
||||
background: var(--c-mist);
|
||||
color: var(--c-ash);
|
||||
background: var(--color-mist);
|
||||
color: var(--color-ash);
|
||||
}
|
||||
|
||||
.int-fb-active {
|
||||
background: var(--c-charcoal);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-charcoal);
|
||||
color: var(--color-paper);
|
||||
transition: all 0.15s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
@@ -620,7 +620,7 @@
|
||||
}
|
||||
|
||||
.int-fb-active.liked {
|
||||
background: var(--c-accent);
|
||||
background: var(--color-accent);
|
||||
animation: heartPop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@
|
||||
|
||||
.int-fb-label {
|
||||
font-size: 0.875rem;
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
@@ -647,10 +647,10 @@
|
||||
.color-palette-after {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
padding: var(--s-md);
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
gap: var(--spacing-xs);
|
||||
padding: var(--spacing-md);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@@ -663,10 +663,10 @@
|
||||
|
||||
.color-card {
|
||||
width: 100%;
|
||||
margin-top: var(--s-sm);
|
||||
padding: var(--s-sm);
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
margin-top: var(--spacing-sm);
|
||||
padding: var(--spacing-sm);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -687,18 +687,18 @@
|
||||
.color-palette-before .card-btn { background: #ffe66d; color: #333; }
|
||||
|
||||
/* After - Harmonious palette */
|
||||
.color-palette-after .swatch-1 { background: var(--c-text); }
|
||||
.color-palette-after .swatch-2 { background: var(--c-charcoal); }
|
||||
.color-palette-after .swatch-3 { background: var(--c-ash); }
|
||||
.color-palette-after .swatch-4 { background: var(--c-mist); }
|
||||
.color-palette-after .swatch-5 { background: var(--c-accent); }
|
||||
.color-palette-after .card-title { color: var(--c-text); }
|
||||
.color-palette-after .card-subtitle { color: var(--c-ash); }
|
||||
.color-palette-after .card-btn { background: var(--c-accent); color: var(--c-paper); }
|
||||
.color-palette-after .swatch-1 { background: var(--color-text); }
|
||||
.color-palette-after .swatch-2 { background: var(--color-charcoal); }
|
||||
.color-palette-after .swatch-3 { background: var(--color-ash); }
|
||||
.color-palette-after .swatch-4 { background: var(--color-mist); }
|
||||
.color-palette-after .swatch-5 { background: var(--color-accent); }
|
||||
.color-palette-after .card-title { color: var(--color-text); }
|
||||
.color-palette-after .card-subtitle { color: var(--color-ash); }
|
||||
.color-palette-after .card-btn { background: var(--color-accent); color: var(--color-paper); }
|
||||
|
||||
/* Strategic Accent */
|
||||
.color-accent-card {
|
||||
padding: var(--s-md);
|
||||
padding: var(--spacing-md);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
@@ -708,27 +708,27 @@
|
||||
}
|
||||
|
||||
.color-accent-before .color-accent-title { font-weight: 600; color: #333; margin-bottom: 4px; }
|
||||
.color-accent-before .color-accent-text { font-size: 0.8125rem; color: #666; margin-bottom: var(--s-sm); }
|
||||
.color-accent-before .color-accent-btn { width: 100%; padding: var(--s-xs); background: #333; color: white; border: none; border-radius: 4px; font-size: 0.8125rem; cursor: pointer; }
|
||||
.color-accent-before .color-accent-text { font-size: 0.8125rem; color: #666; margin-bottom: var(--spacing-sm); }
|
||||
.color-accent-before .color-accent-btn { width: 100%; padding: var(--spacing-xs); background: #333; color: white; border: none; border-radius: 4px; font-size: 0.8125rem; cursor: pointer; }
|
||||
|
||||
.color-accent-after .color-accent-card {
|
||||
background: color-mix(in oklch, var(--c-accent) 8%, var(--c-paper));
|
||||
border: 1px solid color-mix(in oklch, var(--c-accent) 20%, var(--c-paper));
|
||||
background: color-mix(in oklch, var(--color-accent) 8%, var(--color-paper));
|
||||
border: 1px solid color-mix(in oklch, var(--color-accent) 20%, var(--color-paper));
|
||||
}
|
||||
|
||||
.color-accent-after .color-accent-title { font-weight: 600; color: var(--c-text); margin-bottom: 4px; }
|
||||
.color-accent-after .color-accent-text { font-size: 0.8125rem; color: var(--c-ash); margin-bottom: var(--s-sm); }
|
||||
.color-accent-after .color-accent-btn { width: 100%; padding: var(--s-xs); background: var(--c-accent); color: var(--c-paper); border: none; border-radius: 4px; font-size: 0.8125rem; font-weight: 500; cursor: pointer; }
|
||||
.color-accent-after .color-accent-title { font-weight: 600; color: var(--color-text); margin-bottom: 4px; }
|
||||
.color-accent-after .color-accent-text { font-size: 0.8125rem; color: var(--color-ash); margin-bottom: var(--spacing-sm); }
|
||||
.color-accent-after .color-accent-btn { width: 100%; padding: var(--spacing-xs); background: var(--color-accent); color: var(--color-paper); border: none; border-radius: 4px; font-size: 0.8125rem; font-weight: 500; cursor: pointer; }
|
||||
|
||||
/* Contrast Ratios */
|
||||
.color-contrast-static {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.contrast-example {
|
||||
padding: var(--s-md);
|
||||
padding: var(--spacing-md);
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -739,8 +739,8 @@
|
||||
}
|
||||
|
||||
.contrast-pass {
|
||||
background: var(--c-charcoal);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-charcoal);
|
||||
color: var(--color-paper);
|
||||
}
|
||||
|
||||
.contrast-badge {
|
||||
@@ -755,7 +755,7 @@
|
||||
}
|
||||
|
||||
.contrast-fail .contrast-badge { background: #ddd; }
|
||||
.contrast-pass .contrast-badge { background: var(--c-accent); color: var(--c-paper); }
|
||||
.contrast-pass .contrast-badge { background: var(--color-accent); color: var(--color-paper); }
|
||||
|
||||
.contrast-text { font-size: 1rem; font-weight: 500; margin-bottom: 2px; }
|
||||
.contrast-ratio { font-size: 0.6875rem; opacity: 0.7; }
|
||||
@@ -773,20 +773,20 @@
|
||||
.resp-touch-demo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-lg);
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.resp-touch-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.resp-label {
|
||||
font-size: 0.6875rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
@@ -806,36 +806,36 @@
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 0.75rem;
|
||||
background: var(--c-mist);
|
||||
color: var(--c-ash);
|
||||
background: var(--color-mist);
|
||||
color: var(--color-ash);
|
||||
}
|
||||
|
||||
.resp-touch-good button {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
font-size: 1rem;
|
||||
background: var(--c-text);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-text);
|
||||
color: var(--color-paper);
|
||||
}
|
||||
|
||||
/* Fluid Layout */
|
||||
.resp-fluid-demo {
|
||||
padding: var(--s-md);
|
||||
background: var(--c-bg);
|
||||
border: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-md);
|
||||
background: var(--color-bg);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.resp-fluid-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.resp-fluid-fixed,
|
||||
.resp-fluid-adaptive {
|
||||
font-size: 0.75rem;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
}
|
||||
|
||||
.resp-fluid-fixed span,
|
||||
@@ -846,18 +846,18 @@
|
||||
|
||||
.resp-fluid-bar {
|
||||
height: 24px;
|
||||
background: var(--c-mist);
|
||||
background: var(--color-mist);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.resp-fluid-adaptive .resp-fluid-bar {
|
||||
background: var(--c-accent);
|
||||
background: var(--color-accent);
|
||||
}
|
||||
|
||||
/* Adaptive Content */
|
||||
.resp-adapt-demo {
|
||||
display: flex;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
@@ -869,14 +869,14 @@
|
||||
display: block;
|
||||
margin-top: 4px;
|
||||
font-size: 0.625rem;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.resp-device-screen {
|
||||
background: var(--c-paper);
|
||||
border: 2px solid var(--c-mist);
|
||||
background: var(--color-paper);
|
||||
border: 2px solid var(--color-mist);
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
display: flex;
|
||||
@@ -889,7 +889,7 @@
|
||||
.resp-device-desktop .resp-device-screen { width: 120px; height: 70px; }
|
||||
|
||||
.resp-block {
|
||||
background: var(--c-mist);
|
||||
background: var(--color-mist);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
@@ -899,8 +899,8 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.resp-header { height: 16px; background: var(--c-charcoal); }
|
||||
.resp-sidebar { width: 30%; background: var(--c-charcoal); }
|
||||
.resp-header { height: 16px; background: var(--color-charcoal); }
|
||||
.resp-sidebar { width: 30%; background: var(--color-charcoal); }
|
||||
.resp-content { flex: 1; }
|
||||
|
||||
/* ============================================
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* Solution Section - Skills + Commands explanation
|
||||
*/
|
||||
|
||||
.solution-section {
|
||||
padding: var(--s-2xl) 0;
|
||||
border-top: 1px solid var(--c-mist);
|
||||
}
|
||||
|
||||
.solution-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: var(--s-xl);
|
||||
}
|
||||
|
||||
.solution-content {
|
||||
max-width: 680px;
|
||||
}
|
||||
|
||||
.solution-content .section-title {
|
||||
margin-bottom: var(--s-md);
|
||||
}
|
||||
|
||||
.solution-lead {
|
||||
font-size: 1.375rem;
|
||||
line-height: 1.6;
|
||||
color: var(--c-charcoal);
|
||||
}
|
||||
|
||||
.solution-lead strong {
|
||||
color: var(--c-text);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Solution Cards - Side by side */
|
||||
.solution-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--s-lg);
|
||||
|
||||
@media (max-width: 640px) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.solution-card {
|
||||
padding: var(--s-lg);
|
||||
background: var(--c-paper);
|
||||
border-left: 3px solid var(--c-accent);
|
||||
transition: all var(--duration-base) var(--ease-out);
|
||||
}
|
||||
|
||||
.solution-card:hover {
|
||||
background: color-mix(in oklch, var(--c-paper) 90%, var(--c-accent));
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.solution-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: var(--s-md);
|
||||
color: var(--c-accent);
|
||||
}
|
||||
|
||||
.solution-card h3 {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.75rem;
|
||||
font-weight: 400;
|
||||
margin: 0 0 var(--s-sm) 0;
|
||||
color: var(--c-text);
|
||||
}
|
||||
|
||||
.solution-card p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--c-ash);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.solution-card code {
|
||||
font-family: 'Space Grotesk', monospace;
|
||||
font-size: 0.875em;
|
||||
background: color-mix(in oklch, var(--c-accent) 15%, transparent);
|
||||
color: var(--c-accent);
|
||||
padding: 0.125em 0.375em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.solution-card em {
|
||||
font-style: italic;
|
||||
color: var(--c-charcoal);
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/* Design Tokens — Single Source of Truth */
|
||||
|
||||
:root {
|
||||
/* Typography Scale */
|
||||
--font-display: 'Cormorant Garamond', Georgia, serif;
|
||||
--font-body: 'Instrument Sans', system-ui, sans-serif;
|
||||
|
||||
/* Base Colors — Refined Monochrome + Electric Accent */
|
||||
--c-ink: oklch(10% 0 0);
|
||||
--c-paper: oklch(98% 0 0);
|
||||
--c-charcoal: oklch(25% 0 0);
|
||||
--c-ash: oklch(55% 0 0);
|
||||
--c-mist: oklch(92% 0 0);
|
||||
|
||||
/* Semantic aliases for common use */
|
||||
--c-text: var(--c-ink);
|
||||
--c-bg: oklch(96% 0.005 350); /* Very subtle pink tint */
|
||||
|
||||
/* Accent — Vibrant Electric Pink using OKLCH for perceptual uniformity */
|
||||
--c-accent: oklch(60% 0.25 350);
|
||||
--c-accent-hover: oklch(from var(--c-accent) calc(l - 8%) c h);
|
||||
--c-accent-dim: color-mix(in oklch, var(--c-accent), transparent 85%);
|
||||
|
||||
/* Spacing Scale — 8px base unit */
|
||||
--s-unit: 8px;
|
||||
--s-xs: calc(var(--s-unit) * 1); /* 8px */
|
||||
--s-sm: calc(var(--s-unit) * 2); /* 16px */
|
||||
--s-md: calc(var(--s-unit) * 3); /* 24px */
|
||||
--s-lg: calc(var(--s-unit) * 6); /* 48px */
|
||||
--s-xl: calc(var(--s-unit) * 10); /* 80px */
|
||||
--s-2xl: calc(var(--s-unit) * 16); /* 128px */
|
||||
--s-3xl: calc(var(--s-unit) * 24); /* 192px */
|
||||
|
||||
/* Layout Constraints */
|
||||
--max-width: 1280px;
|
||||
--content-width: 840px;
|
||||
|
||||
/* Animation Curves */
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--duration-fast: 0.2s;
|
||||
--duration-base: 0.3s;
|
||||
--duration-slow: 0.6s;
|
||||
--duration-slower: 0.8s;
|
||||
--duration-slowest: 1.2s;
|
||||
|
||||
/* Shadows */
|
||||
--shadow-sm: 0 1px 2px color-mix(in oklch, var(--c-ink), transparent 90%);
|
||||
--shadow-md: 0 4px 8px color-mix(in oklch, var(--c-ink), transparent 85%);
|
||||
}
|
||||
|
||||
/* Dark Mode — Automatic via prefers-color-scheme */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--c-ink: oklch(98% 0 0);
|
||||
--c-paper: oklch(10% 0 0);
|
||||
--c-charcoal: oklch(92% 0 0);
|
||||
--c-ash: oklch(65% 0 0);
|
||||
--c-mist: oklch(20% 0 0);
|
||||
--c-accent: oklch(68% 0.23 350);
|
||||
--c-accent-hover: oklch(from var(--c-accent) calc(l + 8%) c h);
|
||||
--c-text: var(--c-ink);
|
||||
--c-bg: oklch(12% 0.005 350);
|
||||
}
|
||||
}
|
||||
|
||||
+63
-63
@@ -14,7 +14,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
margin-bottom: var(--s-sm);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
@@ -26,10 +26,10 @@
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-ash);
|
||||
padding: var(--s-xs) var(--s-md);
|
||||
color: var(--color-ash);
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
margin-bottom: 2px;
|
||||
margin-top: var(--s-xs);
|
||||
margin-top: var(--spacing-xs);
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
@@ -37,11 +37,11 @@
|
||||
}
|
||||
|
||||
.command-nav-item {
|
||||
padding: var(--s-xs) var(--s-md);
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-left: 2px solid transparent;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-family: 'Space Grotesk', monospace;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 400;
|
||||
@@ -52,14 +52,14 @@
|
||||
}
|
||||
|
||||
.command-nav-item:hover {
|
||||
color: var(--c-text);
|
||||
background: color-mix(in oklch, var(--c-paper) 85%, var(--c-accent));
|
||||
color: var(--color-text);
|
||||
background: color-mix(in oklch, var(--color-paper) 85%, var(--color-accent));
|
||||
}
|
||||
|
||||
.command-nav-item.active {
|
||||
color: var(--c-accent);
|
||||
border-left-color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, var(--c-paper));
|
||||
color: var(--color-accent);
|
||||
border-left-color: var(--color-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, var(--color-paper));
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -67,30 +67,30 @@
|
||||
.commands-nav {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.command-nav-group {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-xs);
|
||||
margin-bottom: var(--s-sm);
|
||||
gap: var(--spacing-xs);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.command-nav-label {
|
||||
width: 100%;
|
||||
padding: var(--s-xs) 0;
|
||||
padding: var(--spacing-xs) 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.command-nav-item {
|
||||
border-left: none;
|
||||
border-bottom: 2px solid transparent;
|
||||
padding: var(--s-xs) var(--s-sm);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
}
|
||||
|
||||
.command-nav-item.active {
|
||||
border-bottom-color: var(--c-accent);
|
||||
border-bottom-color: var(--color-accent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
.workflow-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -107,20 +107,20 @@
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
width: 120px;
|
||||
flex-shrink: 0;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
width: 100%;
|
||||
margin-bottom: var(--s-xs);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-row-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
@@ -130,35 +130,35 @@
|
||||
align-items: center;
|
||||
padding: 4px 10px;
|
||||
background: transparent;
|
||||
border: 1px solid var(--c-mist);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 3px;
|
||||
font-family: 'Space Grotesk', monospace;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
color: var(--c-charcoal);
|
||||
color: var(--color-charcoal);
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
.workflow-node:hover {
|
||||
border-color: var(--c-accent);
|
||||
color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, transparent);
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, transparent);
|
||||
}
|
||||
|
||||
.workflow-node.active {
|
||||
background: var(--c-accent);
|
||||
border-color: var(--c-accent);
|
||||
color: var(--c-paper);
|
||||
background: var(--color-accent);
|
||||
border-color: var(--color-accent);
|
||||
color: var(--color-paper);
|
||||
}
|
||||
|
||||
/* Workflow Arrow */
|
||||
.workflow-arrow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
font-size: 1.25rem;
|
||||
padding: 0 var(--s-xs);
|
||||
padding: 0 var(--spacing-xs);
|
||||
}
|
||||
|
||||
.workflow-arrow-bidirectional::before {
|
||||
@@ -178,17 +178,17 @@
|
||||
.workflow-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
padding: var(--s-sm);
|
||||
background: color-mix(in oklch, var(--c-paper) 50%, transparent);
|
||||
border: 1px dashed var(--c-mist);
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-sm);
|
||||
background: color-mix(in oklch, var(--color-paper) 50%, transparent);
|
||||
border: 1px dashed var(--color-mist);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.workflow-group-label {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 500;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
writing-mode: vertical-lr;
|
||||
@@ -198,7 +198,7 @@
|
||||
writing-mode: horizontal-tb;
|
||||
transform: none;
|
||||
width: 100%;
|
||||
margin-bottom: var(--s-xs);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,20 +206,20 @@
|
||||
.workflow-production {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: var(--s-md);
|
||||
gap: var(--spacing-md);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.workflow-production-stages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.workflow-stage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.workflow-stage-label {
|
||||
@@ -227,21 +227,21 @@
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.workflow-stage-nodes {
|
||||
display: flex;
|
||||
gap: var(--s-xs);
|
||||
gap: var(--spacing-xs);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* Aesthetic Adjustments Section */
|
||||
.workflow-aesthetics {
|
||||
border-top: 1px solid var(--c-mist);
|
||||
padding-top: var(--s-lg);
|
||||
margin-top: var(--s-sm);
|
||||
border-top: 1px solid var(--color-mist);
|
||||
padding-top: var(--spacing-lg);
|
||||
margin-top: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.workflow-aesthetics-title {
|
||||
@@ -249,26 +249,26 @@
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--c-ash);
|
||||
margin-bottom: var(--s-md);
|
||||
color: var(--color-ash);
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.workflow-pairs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-lg);
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.workflow-pair {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--s-sm);
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.workflow-container {
|
||||
padding: var(--s-md);
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.workflow-production {
|
||||
@@ -282,15 +282,15 @@
|
||||
|
||||
.workflow-stage-label {
|
||||
width: auto;
|
||||
margin-bottom: var(--s-xs);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Command Card in Grid */
|
||||
.command-card {
|
||||
padding: var(--s-sm) var(--s-md);
|
||||
background: var(--c-paper);
|
||||
border: 1px solid var(--c-mist);
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background: var(--color-paper);
|
||||
border: 1px solid var(--color-mist);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
transition: all var(--duration-fast) var(--ease-out);
|
||||
@@ -298,27 +298,27 @@
|
||||
}
|
||||
|
||||
.command-card:hover {
|
||||
border-color: var(--c-accent);
|
||||
border-color: var(--color-accent);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px color-mix(in oklch, var(--c-accent) 10%, transparent);
|
||||
box-shadow: 0 4px 12px color-mix(in oklch, var(--color-accent) 10%, transparent);
|
||||
}
|
||||
|
||||
.command-card.active {
|
||||
border-color: var(--c-accent);
|
||||
background: color-mix(in oklch, var(--c-accent) 5%, var(--c-paper));
|
||||
border-color: var(--color-accent);
|
||||
background: color-mix(in oklch, var(--color-accent) 5%, var(--color-paper));
|
||||
}
|
||||
|
||||
.command-card-name {
|
||||
font-family: 'Space Grotesk', monospace;
|
||||
font-size: 0.9375rem;
|
||||
font-weight: 500;
|
||||
color: var(--c-text);
|
||||
color: var(--color-text);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.command-card-desc {
|
||||
font-size: 0.75rem;
|
||||
color: var(--c-ash);
|
||||
color: var(--color-ash);
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
@@ -334,9 +334,9 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
padding: 2px 6px;
|
||||
background: var(--c-mist);
|
||||
color: var(--c-ash);
|
||||
background: var(--color-mist);
|
||||
color: var(--color-ash);
|
||||
border-radius: 2px;
|
||||
margin-top: var(--s-xs);
|
||||
margin-top: var(--spacing-xs);
|
||||
}
|
||||
|
||||
|
||||
+69
-68
@@ -7,37 +7,38 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;0,700;1,300;1,400&family=Instrument+Sans:wght@400;500;600;700&family=Inter:wght@400;500;600&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="tailwindcss" />
|
||||
<link rel="stylesheet" href="./css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<body class="min-h-screen overflow-x-hidden leading-relaxed">
|
||||
<!-- 1. HERO - Hook with the problem statement -->
|
||||
<header class="hero">
|
||||
<div class="hero-grid">
|
||||
<header class="min-h-[85vh] flex items-center relative py-32 px-12 overflow-hidden max-md:min-h-[70vh] max-md:py-20 max-md:px-6">
|
||||
<div class="max-w-max mx-auto grid grid-cols-[1fr_auto] gap-32 items-center w-full relative max-md:grid-cols-1 max-md:gap-20">
|
||||
<div class="hero-content">
|
||||
<h1 class="title">
|
||||
<span class="title-main">Impeccable style</span>
|
||||
<span class="title-sub">made easy</span>
|
||||
<h1 class="font-display text-[clamp(3rem,8vw,7rem)] font-light leading-[0.9] mb-12 flex flex-col max-md:text-[clamp(2.5rem,12vw,4rem)]">
|
||||
<span class="font-normal tracking-tight">Impeccable style</span>
|
||||
<span class="font-light italic text-accent tracking-tight">made easy</span>
|
||||
</h1>
|
||||
<p class="tagline">Your LLM can design beautiful interfaces.<br>It just needs to know what to ask for.</p>
|
||||
<p class="providers">Works with Cursor · Claude Code · Gemini CLI · Codex CLI</p>
|
||||
<p class="text-[clamp(1.125rem,2vw,1.5rem)] leading-snug text-charcoal mb-6 max-w-[32ch]">Your LLM can design beautiful interfaces.<br>It just needs to know what to ask for.</p>
|
||||
<p class="text-sm text-ash uppercase tracking-widest font-medium">Works with Cursor · Claude Code · Gemini CLI · Codex CLI</p>
|
||||
</div>
|
||||
<div class="hero-decoration" aria-hidden="true">
|
||||
<div class="hero-decoration w-60 h-60 relative max-md:hidden" aria-hidden="true">
|
||||
<div class="deco-line"></div>
|
||||
<div class="deco-circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<main class="max-w-max mx-auto px-12 max-sm:px-6">
|
||||
<!-- 2. THE PROBLEM - Show the "AI slop" aesthetic -->
|
||||
<section class="problem-section">
|
||||
<div class="problem-grid">
|
||||
<div class="problem-content">
|
||||
<h2 class="section-title">The Problem</h2>
|
||||
<p class="problem-lead">LLMs are biased toward safe, generic design choices. Without guidance, you get the same predictable aesthetic every time.</p>
|
||||
<section class="problem-section py-32 border-t border-mist">
|
||||
<div class="problem-grid grid grid-cols-2 gap-32 items-center max-lg:grid-cols-1 max-lg:gap-20">
|
||||
<div class="max-w-md">
|
||||
<h2 class="section-title mb-6">The Problem</h2>
|
||||
<p class="text-xl leading-relaxed text-charcoal">LLMs are biased toward safe, generic design choices. Without guidance, you get the same predictable aesthetic every time.</p>
|
||||
</div>
|
||||
<div class="problem-showcase">
|
||||
<div class="ai-slop-demo">
|
||||
<div class="problem-showcase flex justify-center">
|
||||
<div class="ai-slop-demo relative max-w-sm w-full">
|
||||
<div class="slop-card">
|
||||
<div class="slop-header">
|
||||
<div class="slop-avatar"></div>
|
||||
@@ -61,118 +62,118 @@
|
||||
</section>
|
||||
|
||||
<!-- 3. THE SOLUTION - Brief explanation -->
|
||||
<section class="solution-section">
|
||||
<div class="solution-grid">
|
||||
<div class="solution-content">
|
||||
<h2 class="section-title">The Solution</h2>
|
||||
<p class="solution-lead">Teach your AI assistant the language of design. <strong>Skills</strong> provide deep design knowledge. <strong>Commands</strong> give you precise control over the creative process.</p>
|
||||
<section class="py-32 border-t border-mist">
|
||||
<div class="grid gap-20">
|
||||
<div class="max-w-2xl">
|
||||
<h2 class="section-title mb-6">The Solution</h2>
|
||||
<p class="text-[1.375rem] leading-relaxed text-charcoal">Teach your AI assistant the language of design. <strong class="text-ink font-semibold">Skills</strong> provide deep design knowledge. <strong class="text-ink font-semibold">Commands</strong> give you precise control over the creative process.</p>
|
||||
</div>
|
||||
<div class="solution-cards">
|
||||
<div class="grid grid-cols-2 gap-12 max-sm:grid-cols-1">
|
||||
<div class="solution-card">
|
||||
<div class="solution-icon">
|
||||
<div class="w-12 h-12 flex items-center justify-center mb-6 text-accent">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>8 Skills</h3>
|
||||
<p>Deep knowledge in typography, color, motion, spatial design, and more. The AI learns <em>how</em> to think about design.</p>
|
||||
<h3 class="font-display text-3xl font-normal mb-4">8 Skills</h3>
|
||||
<p class="text-base leading-relaxed text-ash">Deep knowledge in typography, color, motion, spatial design, and more. The AI learns <em class="italic text-charcoal">how</em> to think about design.</p>
|
||||
</div>
|
||||
<div class="solution-card">
|
||||
<div class="solution-icon">
|
||||
<div class="w-12 h-12 flex items-center justify-center mb-6 text-accent">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M6.75 7.5l3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0021 18V6a2.25 2.25 0 00-2.25-2.25H5.25A2.25 2.25 0 003 6v12a2.25 2.25 0 002.25 2.25z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>15 Commands</h3>
|
||||
<p>Precise actions like <code>/bolder</code>, <code>/animate</code>, <code>/audit</code>. Steer the AI through iterative design refinement.</p>
|
||||
<h3 class="font-display text-3xl font-normal mb-4">15 Commands</h3>
|
||||
<p class="text-base leading-relaxed text-ash">Precise actions like <code>/bolder</code>, <code>/animate</code>, <code>/audit</code>. Steer the AI through iterative design refinement.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 4. SKILLS SHOWCASE - Interactive demos -->
|
||||
<section class="skills-section" id="skills-section">
|
||||
<div class="section-header-sticky">
|
||||
<h2 class="section-title">Skills</h2>
|
||||
<p class="section-subtitle">Design knowledge that transforms AI output</p>
|
||||
<section class="skills-section py-20 border-t border-mist" id="skills-section">
|
||||
<div class="mb-12">
|
||||
<h2 class="section-title mb-4">Skills</h2>
|
||||
<p class="text-lg text-ash mt-6 max-w-[50ch]">Design knowledge that transforms AI output</p>
|
||||
</div>
|
||||
<div class="skills-layout">
|
||||
<nav class="skills-nav" id="skills-nav">
|
||||
<div class="loading">Loading...</div>
|
||||
<div class="skills-layout grid grid-cols-[180px_1fr] gap-12 items-start max-lg:grid-cols-1 max-lg:gap-6">
|
||||
<nav class="skills-nav flex flex-col gap-0.5 max-lg:flex-row max-lg:flex-wrap max-lg:gap-2" id="skills-nav">
|
||||
<div class="py-20 text-center text-ash italic">Loading...</div>
|
||||
</nav>
|
||||
<div class="skills-showcase" id="skills-detail">
|
||||
<div class="loading">Select a skill to see it in action</div>
|
||||
<div class="py-20 text-center text-ash italic">Select a skill to see it in action</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 5. COMMANDS - Sidebar nav + details (mirrors skills layout) -->
|
||||
<section class="commands-section" id="commands-section">
|
||||
<div class="section-header-sticky">
|
||||
<h2 class="section-title">Commands</h2>
|
||||
<p class="section-subtitle">Precise control over the design process</p>
|
||||
<section class="commands-section py-20 border-t border-mist" id="commands-section">
|
||||
<div class="mb-12">
|
||||
<h2 class="section-title mb-4">Commands</h2>
|
||||
<p class="text-lg text-ash mt-6 max-w-[50ch]">Precise control over the design process</p>
|
||||
</div>
|
||||
|
||||
<div class="commands-layout">
|
||||
<div class="commands-layout grid grid-cols-[180px_1fr] gap-12 items-start max-lg:grid-cols-1 max-lg:gap-6">
|
||||
<!-- Commands nav (left sidebar) -->
|
||||
<nav class="commands-nav" id="workflow-diagram">
|
||||
<nav class="commands-nav flex flex-col gap-4 max-lg:flex-row max-lg:flex-wrap max-lg:gap-2" id="workflow-diagram">
|
||||
<!-- Will be rendered by JS -->
|
||||
</nav>
|
||||
|
||||
<!-- Command detail (right side) -->
|
||||
<div class="commands-showcase" id="commands-detail">
|
||||
<div class="loading">Select a command to view details</div>
|
||||
<div class="py-20 text-center text-ash italic">Select a command to view details</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 6. DOWNLOAD BUNDLES - After demonstrating value -->
|
||||
<section class="downloads-section" id="downloads">
|
||||
<div class="downloads-header">
|
||||
<h2 class="section-title">Get Started</h2>
|
||||
<p class="downloads-lead">Download the complete bundle for your preferred AI tool. Extract into your project root and start creating.</p>
|
||||
<section class="py-32 border-t border-mist" id="downloads">
|
||||
<div class="mb-20 max-w-xl">
|
||||
<h2 class="section-title mb-6">Get Started</h2>
|
||||
<p class="text-lg leading-relaxed text-ash">Download the complete bundle for your preferred AI tool. Extract into your project root and start creating.</p>
|
||||
</div>
|
||||
<div class="download-grid">
|
||||
<div class="grid grid-cols-[repeat(auto-fit,minmax(260px,1fr))] gap-6 max-sm:grid-cols-1">
|
||||
<article class="download-card" data-animate>
|
||||
<div class="card-inner">
|
||||
<div class="card-header">
|
||||
<h3>Cursor</h3>
|
||||
<div class="flex justify-between items-start gap-6">
|
||||
<h3 class="font-display text-xl font-medium">Cursor</h3>
|
||||
<span class="badge">Rules + Commands</span>
|
||||
</div>
|
||||
<p>Commands and rules for Cursor IDE. Works via appending, no frontmatter required.</p>
|
||||
<p class="text-ash text-[0.9375rem] leading-relaxed flex-grow">Commands and rules for Cursor IDE. Works via appending, no frontmatter required.</p>
|
||||
<button class="btn btn-primary" data-bundle="cursor">Download</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="download-card" data-animate>
|
||||
<div class="card-inner">
|
||||
<div class="card-header">
|
||||
<h3>Claude Code</h3>
|
||||
<div class="flex justify-between items-start gap-6">
|
||||
<h3 class="font-display text-xl font-medium">Claude Code</h3>
|
||||
<span class="badge">Full Featured</span>
|
||||
</div>
|
||||
<p>Complete YAML frontmatter with argument support. Follows Anthropic Skills specification.</p>
|
||||
<p class="text-ash text-[0.9375rem] leading-relaxed flex-grow">Complete YAML frontmatter with argument support. Follows Anthropic Skills specification.</p>
|
||||
<button class="btn btn-primary" data-bundle="claude-code">Download</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="download-card" data-animate>
|
||||
<div class="card-inner">
|
||||
<div class="card-header">
|
||||
<h3>Gemini CLI</h3>
|
||||
<div class="flex justify-between items-start gap-6">
|
||||
<h3 class="font-display text-xl font-medium">Gemini CLI</h3>
|
||||
<span class="badge">TOML + Modular</span>
|
||||
</div>
|
||||
<p>TOML-formatted commands with modular skill imports via GEMINI.md.</p>
|
||||
<p class="text-ash text-[0.9375rem] leading-relaxed flex-grow">TOML-formatted commands with modular skill imports via GEMINI.md.</p>
|
||||
<button class="btn btn-primary" data-bundle="gemini">Download</button>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="download-card" data-animate>
|
||||
<div class="card-inner">
|
||||
<div class="card-header">
|
||||
<h3>Codex CLI</h3>
|
||||
<div class="flex justify-between items-start gap-6">
|
||||
<h3 class="font-display text-xl font-medium">Codex CLI</h3>
|
||||
<span class="badge">Prompts + Routing</span>
|
||||
</div>
|
||||
<p>Custom prompt format with skill routing through AGENTS.md architecture.</p>
|
||||
<p class="text-ash text-[0.9375rem] leading-relaxed flex-grow">Custom prompt format with skill routing through AGENTS.md architecture.</p>
|
||||
<button class="btn btn-primary" data-bundle="codex">Download</button>
|
||||
</div>
|
||||
</article>
|
||||
@@ -180,19 +181,19 @@
|
||||
</section>
|
||||
|
||||
<!-- 7. OPEN SOURCE -->
|
||||
<section class="contribute">
|
||||
<div class="contribute-content">
|
||||
<h2>Open Source</h2>
|
||||
<p>View the source, contribute skills and commands, or report issues on GitHub.</p>
|
||||
<section class="py-32 border-t border-mist text-center">
|
||||
<div class="max-w-md mx-auto flex flex-col items-center gap-6">
|
||||
<h2 class="font-display text-[clamp(2rem,4vw,3rem)] font-semibold">Open Source</h2>
|
||||
<p class="text-lg text-ash max-w-[42ch]">View the source, contribute skills and commands, or report issues on GitHub.</p>
|
||||
<a href="https://github.com/pbakaus/vibe-design-plugins" class="btn btn-secondary">View Repository</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="footer-content">
|
||||
<footer class="border-t border-mist py-32 px-12 bg-paper">
|
||||
<div class="max-w-max mx-auto flex justify-between items-center text-sm text-ash max-md:flex-col max-md:gap-4 max-md:text-center">
|
||||
<p>impeccable.style</p>
|
||||
<p><a href="https://github.com/pbakaus/vibe-design-plugins">GitHub</a></p>
|
||||
<p><a href="https://github.com/pbakaus/vibe-design-plugins" class="text-ink underline underline-offset-2">GitHub</a></p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
// ============================================
|
||||
// COMMAND DEMOS - Before/after demonstrations for commands
|
||||
// ============================================
|
||||
|
||||
export function renderCommandDemo(commandId) {
|
||||
const demos = {
|
||||
'bolder': renderBolderDemo,
|
||||
'animate': renderAnimateDemo,
|
||||
'normalize': renderNormalizeDemo
|
||||
};
|
||||
|
||||
const renderFn = demos[commandId];
|
||||
if (renderFn) return renderFn();
|
||||
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<span class="demo-title">Command Preview</span>
|
||||
</div>
|
||||
<div class="demo-viewport">
|
||||
<div style="text-align: center; color: var(--c-ash); font-style: italic;">
|
||||
Visual demo for /${commandId} coming soon
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderBolderDemo() {
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<span class="demo-title">Before / After</span>
|
||||
<div class="demo-toggle">
|
||||
<span class="demo-toggle-label active">Before</span>
|
||||
<div class="demo-toggle-switch" data-demo="command-bolder"></div>
|
||||
<span class="demo-toggle-label">After</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-viewport" data-state="before" id="command-bolder-viewport">
|
||||
<div style="text-align: center; padding: var(--s-md); max-width: 280px;">
|
||||
<div style="font-size: 1.125rem; font-weight: 500; margin-bottom: 8px; color: var(--c-charcoal);">Introducing Our Product</div>
|
||||
<div style="font-size: 0.875rem; color: var(--c-ash); margin-bottom: 16px;">A solution for modern teams</div>
|
||||
<button style="padding: 8px 16px; background: var(--c-mist); color: var(--c-charcoal); border: none; border-radius: 4px; font-size: 0.875rem;">Learn More</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-caption">Timid design → Bold, confident design</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderAnimateDemo() {
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<span class="demo-title">Before / After</span>
|
||||
<div class="demo-toggle">
|
||||
<span class="demo-toggle-label active">Before</span>
|
||||
<div class="demo-toggle-switch" data-demo="command-animate"></div>
|
||||
<span class="demo-toggle-label">After</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-viewport demo-viewport-dark" data-state="before" id="command-animate-viewport">
|
||||
<div class="motion-demo-page" style="opacity: 1;">
|
||||
<div class="motion-demo-page-hero" style="opacity: 1; transform: none;">Hero</div>
|
||||
<div class="motion-demo-page-content">
|
||||
<div class="motion-demo-page-heading" style="opacity: 1; transform: none;"></div>
|
||||
<div class="motion-demo-page-text" style="opacity: 1; transform: none;"></div>
|
||||
<div class="motion-demo-page-text" style="opacity: 1; transform: none;"></div>
|
||||
<div class="motion-demo-page-text" style="opacity: 1; transform: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-caption">Static page → Choreographed page load</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderNormalizeDemo() {
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<span class="demo-title">Before / After</span>
|
||||
<div class="demo-toggle">
|
||||
<span class="demo-toggle-label active">Before</span>
|
||||
<div class="demo-toggle-switch" data-demo="command-normalize"></div>
|
||||
<span class="demo-toggle-label">After</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-viewport" data-state="before" id="command-normalize-viewport">
|
||||
<div style="display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 260px;">
|
||||
<div style="padding: 12px 16px; background: #f0f0f0; border-radius: 6px;">
|
||||
<div style="font-size: 14px; font-weight: 600; margin-bottom: 4px;">Card One</div>
|
||||
<div style="font-size: 13px; color: #888;">Some description text here</div>
|
||||
</div>
|
||||
<div style="padding: 18px 12px; background: #e8e8e8; border-radius: 12px;">
|
||||
<div style="font-size: 16px; font-weight: 500; margin-bottom: 8px;">Card Two</div>
|
||||
<div style="font-size: 14px; color: #666;">Different spacing and styles</div>
|
||||
</div>
|
||||
<div style="padding: 10px 20px; background: #f5f5f5; border-radius: 4px;">
|
||||
<div style="font-size: 15px; font-weight: 700; margin-bottom: 2px;">Card Three</div>
|
||||
<div style="font-size: 12px; color: #999;">Yet another variation</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-caption">Inconsistent styles → Systematic design tokens</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
+23
-8
@@ -2,13 +2,13 @@
|
||||
// COMMANDS - Rendering, workflow, and category logic
|
||||
// ============================================
|
||||
|
||||
import { renderCommandDemo } from "./command-demos.js";
|
||||
import {
|
||||
commandCategories,
|
||||
commandProcessSteps,
|
||||
commandRelationships,
|
||||
readyCommands,
|
||||
} from "./data.js";
|
||||
import { renderCommandDemo } from "./demo-renderer.js";
|
||||
import { setupCommandDemoToggles } from "./demo-toggles.js";
|
||||
|
||||
let currentCommand = null;
|
||||
@@ -25,28 +25,43 @@ export function renderWorkflowDiagram(allCommands, onSelectCommand) {
|
||||
|
||||
// Group commands by category for the sidebar
|
||||
const groups = {
|
||||
production: ['audit', 'normalize', 'adapt', 'clarify', 'harden', 'optimize', 'polish'],
|
||||
aesthetic: ['bolder', 'quieter', 'animate', 'delight', 'colorize', 'simplify'],
|
||||
system: ['extract', 'onboard']
|
||||
production: [
|
||||
"audit",
|
||||
"normalize",
|
||||
"adapt",
|
||||
"clarify",
|
||||
"harden",
|
||||
"optimize",
|
||||
"polish",
|
||||
],
|
||||
aesthetic: [
|
||||
"bolder",
|
||||
"quieter",
|
||||
"animate",
|
||||
"delight",
|
||||
"colorize",
|
||||
"simplify",
|
||||
],
|
||||
system: ["extract", "onboard"],
|
||||
};
|
||||
|
||||
const renderNavItem = (id) => {
|
||||
const ready = isCommandReady(id);
|
||||
return `<button class="command-nav-item ${!ready ? 'coming-soon' : ''}" data-command="${id}">/${id}${!ready ? '<span class="coming-soon-badge">Soon</span>' : ''}</button>`;
|
||||
return `<button class="command-nav-item ${!ready ? "coming-soon" : ""}" data-command="${id}">/${id}${!ready ? '<span class="coming-soon-badge">Soon</span>' : ""}</button>`;
|
||||
};
|
||||
|
||||
container.innerHTML = `
|
||||
<div class="command-nav-group">
|
||||
<span class="command-nav-label">Production</span>
|
||||
${groups.production.map(renderNavItem).join('')}
|
||||
${groups.production.map(renderNavItem).join("")}
|
||||
</div>
|
||||
<div class="command-nav-group">
|
||||
<span class="command-nav-label">Aesthetic</span>
|
||||
${groups.aesthetic.map(renderNavItem).join('')}
|
||||
${groups.aesthetic.map(renderNavItem).join("")}
|
||||
</div>
|
||||
<div class="command-nav-group">
|
||||
<span class="command-nav-label">System</span>
|
||||
${groups.system.map(renderNavItem).join('')}
|
||||
${groups.system.map(renderNavItem).join("")}
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
// ============================================
|
||||
// DEMO RENDERER - Generic rendering for command and skill demos
|
||||
// ============================================
|
||||
|
||||
import { getCommandDemo } from './demos/commands/index.js';
|
||||
import { getSkillDemo } from './demos/skills/index.js';
|
||||
|
||||
/**
|
||||
* Render a command demo
|
||||
*/
|
||||
export function renderCommandDemo(commandId) {
|
||||
const demo = getCommandDemo(commandId);
|
||||
|
||||
if (!demo) {
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-viewport">
|
||||
<div style="text-align: center; color: var(--color-ash); font-style: italic; padding: var(--spacing-lg);">
|
||||
Visual demo for /${commandId} coming soon
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const viewportClass = demo.viewportClass ? ` ${demo.viewportClass}` : '';
|
||||
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<div class="demo-toggle">
|
||||
<span class="demo-toggle-label active">Before</span>
|
||||
<div class="demo-toggle-switch" data-demo="command-${demo.id}"></div>
|
||||
<span class="demo-toggle-label">After</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="demo-viewport${viewportClass}" data-state="before" id="command-${demo.id}-viewport">
|
||||
${demo.before}
|
||||
</div>
|
||||
<div class="demo-caption">${demo.caption}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a skill demo (with tabs if multiple demos)
|
||||
*/
|
||||
export function renderSkillDemo(skillId) {
|
||||
const skill = getSkillDemo(skillId);
|
||||
|
||||
if (!skill || !skill.tabs || skill.tabs.length === 0) {
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-viewport">
|
||||
<div style="text-align: center; color: var(--color-ash); padding: var(--spacing-xl);">
|
||||
<p>Demo for ${skillId.replace(/-/g, ' ')} coming soon</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const showTabs = skill.tabs.length > 1;
|
||||
|
||||
const tabs = showTabs ? skill.tabs.map((tab, i) => `
|
||||
<button class="demo-tab ${i === 0 ? 'active' : ''}" data-demo-tab="${tab.id}" data-skill="${skillId}">
|
||||
${tab.label}
|
||||
</button>
|
||||
`).join('') : '';
|
||||
|
||||
const panels = skill.tabs.map((tab, i) => `
|
||||
<div class="demo-panel ${i === 0 ? 'active' : ''}" data-demo-panel="${tab.id}">
|
||||
${renderSkillTabDemo(skillId, tab)}
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
return `
|
||||
<div class="demo-tabbed-container">
|
||||
${showTabs ? `<div class="demo-tabs">${tabs}</div>` : ''}
|
||||
<div class="demo-panels">
|
||||
${panels}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a single skill tab demo
|
||||
*/
|
||||
function renderSkillTabDemo(skillId, tab) {
|
||||
const hasToggle = tab.hasToggle !== false;
|
||||
const demoId = `${skillId}-${tab.id}`;
|
||||
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
${hasToggle ? `
|
||||
<div class="demo-toggle">
|
||||
<span class="demo-toggle-label active">Before</span>
|
||||
<div class="demo-toggle-switch" data-demo="${demoId}"></div>
|
||||
<span class="demo-toggle-label">After</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="demo-viewport" data-state="before" id="${demoId}-viewport">
|
||||
${tab.before}
|
||||
</div>
|
||||
<div class="demo-caption">${tab.caption}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup demo tab switching
|
||||
*/
|
||||
export function setupDemoTabs() {
|
||||
document.querySelectorAll('.demo-tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const tabId = tab.dataset.demoTab;
|
||||
const container = tab.closest('.demo-tabbed-container');
|
||||
|
||||
container.querySelectorAll('.demo-tab').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
container.querySelectorAll('.demo-panel').forEach(p => p.classList.remove('active'));
|
||||
container.querySelector(`[data-demo-panel="${tabId}"]`)?.classList.add('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
+78
-344
@@ -2,8 +2,18 @@
|
||||
// DEMO TOGGLES - Handle before/after toggle interactions
|
||||
// ============================================
|
||||
|
||||
import { getCommandDemo } from './demos/commands/index.js';
|
||||
import { getSkillDemo } from './demos/skills/index.js';
|
||||
|
||||
/**
|
||||
* Setup toggle handlers for skill demos
|
||||
*/
|
||||
export function setupDemoToggles() {
|
||||
document.querySelectorAll('.demo-toggle-switch').forEach(toggle => {
|
||||
// Skip if already has handler
|
||||
if (toggle.dataset.initialized) return;
|
||||
toggle.dataset.initialized = 'true';
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
const demoId = toggle.dataset.demo;
|
||||
const isActive = toggle.classList.toggle('active');
|
||||
@@ -22,8 +32,15 @@ export function setupDemoToggles() {
|
||||
setupInteractiveButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup toggle handlers for command demos
|
||||
*/
|
||||
export function setupCommandDemoToggles(allCommands, selectCommand) {
|
||||
document.querySelectorAll('.command-demo-area .demo-toggle-switch').forEach(toggle => {
|
||||
// Skip if already has handler
|
||||
if (toggle.dataset.initialized) return;
|
||||
toggle.dataset.initialized = 'true';
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
const demoId = toggle.dataset.demo;
|
||||
const isActive = toggle.classList.toggle('active');
|
||||
@@ -45,376 +62,93 @@ export function setupCommandDemoToggles(allCommands, selectCommand) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup interactive demo buttons (like the "like" button)
|
||||
*/
|
||||
function setupInteractiveButtons() {
|
||||
// Like button feedback demo
|
||||
document.querySelectorAll('.int-fb-active[data-action="like"]').forEach(btn => {
|
||||
if (btn.dataset.initialized) return;
|
||||
btn.dataset.initialized = 'true';
|
||||
|
||||
btn.addEventListener('click', () => {
|
||||
btn.classList.toggle('liked');
|
||||
const label = btn.nextElementSibling;
|
||||
if (label) {
|
||||
label.textContent = btn.classList.contains('liked') ? 'Liked!' : 'Click me!';
|
||||
label.textContent = btn.classList.contains('liked') ? 'Liked!' : 'Click to try!';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle skill demo toggle
|
||||
*/
|
||||
function handleDemoToggle(demoId, isAfter) {
|
||||
const viewport = document.getElementById(`${demoId}-viewport`);
|
||||
if (!viewport) return;
|
||||
|
||||
viewport.dataset.state = isAfter ? 'after' : 'before';
|
||||
|
||||
// Handle specific demo transformations
|
||||
switch (demoId) {
|
||||
// UX Writing
|
||||
case 'uxwriting-error':
|
||||
toggleUXError(viewport, isAfter);
|
||||
break;
|
||||
case 'uxwriting-buttons':
|
||||
toggleUXButtons(viewport, isAfter);
|
||||
break;
|
||||
case 'uxwriting-empty':
|
||||
toggleUXEmpty(viewport, isAfter);
|
||||
break;
|
||||
|
||||
// Spatial Design
|
||||
case 'spatial-grid':
|
||||
toggleSpatialGrid(viewport, isAfter);
|
||||
break;
|
||||
case 'spatial-hierarchy':
|
||||
toggleSpatialHierarchy(viewport, isAfter);
|
||||
break;
|
||||
case 'spatial-whitespace':
|
||||
toggleSpatialWhitespace(viewport, isAfter);
|
||||
break;
|
||||
|
||||
// Motion Design
|
||||
case 'motion-stagger':
|
||||
toggleMotionStagger(viewport, isAfter);
|
||||
break;
|
||||
case 'motion-micro':
|
||||
toggleMotionMicro(viewport, isAfter);
|
||||
break;
|
||||
case 'motion-transition':
|
||||
toggleMotionTransition(viewport, isAfter);
|
||||
break;
|
||||
|
||||
// Typography
|
||||
case 'typography-pairing':
|
||||
toggleTypoPairing(viewport, isAfter);
|
||||
break;
|
||||
case 'typography-hierarchy':
|
||||
toggleTypoHierarchy(viewport, isAfter);
|
||||
break;
|
||||
|
||||
// Interaction Design
|
||||
case 'interaction-states':
|
||||
// No content change needed - CSS handles it
|
||||
break;
|
||||
case 'interaction-affordance':
|
||||
toggleAffordance(viewport, isAfter);
|
||||
break;
|
||||
case 'interaction-feedback':
|
||||
toggleFeedback(viewport, isAfter);
|
||||
break;
|
||||
|
||||
// Color & Contrast
|
||||
case 'color-palette':
|
||||
toggleColorPalette(viewport, isAfter);
|
||||
break;
|
||||
case 'color-accent':
|
||||
toggleColorAccent(viewport, isAfter);
|
||||
break;
|
||||
// Parse skill ID and tab ID from demoId (e.g., "ux-writing-errors")
|
||||
const parts = demoId.split('-');
|
||||
const tabId = parts.pop();
|
||||
const skillId = parts.join('-');
|
||||
|
||||
const skill = getSkillDemo(skillId);
|
||||
if (!skill) return;
|
||||
|
||||
const tab = skill.tabs.find(t => t.id === tabId);
|
||||
if (!tab) return;
|
||||
|
||||
// Check for custom toggle handler
|
||||
if (tab.onToggle) {
|
||||
tab.onToggle(viewport, isAfter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== UX WRITING ==========
|
||||
|
||||
function toggleUXError(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.uxw-demo');
|
||||
if (!demo) return;
|
||||
|
||||
if (isAfter) {
|
||||
demo.className = 'uxw-demo uxw-error-after';
|
||||
demo.innerHTML = `
|
||||
<div class="uxw-error-icon">🔐</div>
|
||||
<div class="uxw-error-title">You don't have access</div>
|
||||
<div class="uxw-error-text">Your session may have expired. Sign in again to continue.</div>
|
||||
<div class="uxw-error-action">Sign in →</div>
|
||||
`;
|
||||
} else {
|
||||
demo.className = 'uxw-demo uxw-error-before';
|
||||
demo.innerHTML = `
|
||||
<div class="uxw-error-icon">⚠</div>
|
||||
<div class="uxw-error-title">Error 403</div>
|
||||
<div class="uxw-error-text">Access denied. Authentication failure occurred.</div>
|
||||
`;
|
||||
// Check for CSS class toggle
|
||||
if (tab.beforeClass && tab.afterClass) {
|
||||
const demo = viewport.firstElementChild;
|
||||
if (demo) {
|
||||
demo.className = isAfter ? tab.afterClass : tab.beforeClass;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUXButtons(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.uxw-demo');
|
||||
if (!demo) return;
|
||||
|
||||
if (isAfter) {
|
||||
demo.innerHTML = `
|
||||
<div class="uxw-button-context">Delete account permanently?</div>
|
||||
<div class="uxw-button-row">
|
||||
<button class="uxw-btn uxw-btn-danger">Delete My Account</button>
|
||||
<button class="uxw-btn uxw-btn-secondary">Keep Account</button>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
demo.innerHTML = `
|
||||
<div class="uxw-button-context">Delete account permanently?</div>
|
||||
<div class="uxw-button-row">
|
||||
<button class="uxw-btn uxw-btn-primary">Submit</button>
|
||||
<button class="uxw-btn uxw-btn-secondary">Cancel</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUXEmpty(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.uxw-demo');
|
||||
if (!demo) return;
|
||||
|
||||
if (isAfter) {
|
||||
demo.className = 'uxw-demo uxw-empty-after';
|
||||
demo.innerHTML = `
|
||||
<div class="uxw-empty-icon">📝</div>
|
||||
<div class="uxw-empty-title">No projects yet</div>
|
||||
<div class="uxw-empty-text">Create your first project to get started.</div>
|
||||
<div class="uxw-empty-action"><button class="uxw-btn uxw-btn-primary">Create Project</button></div>
|
||||
`;
|
||||
} else {
|
||||
demo.className = 'uxw-demo uxw-empty-before';
|
||||
demo.innerHTML = `
|
||||
<div class="uxw-empty-icon">📁</div>
|
||||
<div class="uxw-empty-title">No items</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== SPATIAL DESIGN ==========
|
||||
|
||||
function toggleSpatialGrid(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.spatial-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'spatial-demo spatial-grid-after' : 'spatial-demo spatial-grid-before';
|
||||
|
||||
// Reset inline styles on children
|
||||
demo.querySelectorAll('.spatial-card-item').forEach((item, i) => {
|
||||
item.style.width = isAfter ? '' : ['45%', '30%', '55%', '25%'][i];
|
||||
});
|
||||
}
|
||||
|
||||
function toggleSpatialHierarchy(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.spatial-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'spatial-demo spatial-hierarchy-after' : 'spatial-demo spatial-hierarchy-before';
|
||||
}
|
||||
|
||||
function toggleSpatialWhitespace(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.spatial-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'spatial-demo spatial-whitespace-after' : 'spatial-demo spatial-whitespace-before';
|
||||
}
|
||||
|
||||
// ========== MOTION DESIGN ==========
|
||||
|
||||
function toggleMotionStagger(viewport, isAfter) {
|
||||
if (isAfter) {
|
||||
// Trigger re-animation by cloning elements
|
||||
const items = viewport.querySelectorAll('.motion-list-item');
|
||||
items.forEach(item => {
|
||||
const clone = item.cloneNode(true);
|
||||
item.parentNode.replaceChild(clone, item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleMotionMicro(viewport, isAfter) {
|
||||
const btn = viewport.querySelector('.motion-btn');
|
||||
if (!btn) return;
|
||||
|
||||
btn.className = isAfter ? 'motion-btn motion-btn-after' : 'motion-btn motion-btn-before';
|
||||
}
|
||||
|
||||
function toggleMotionTransition(viewport, isAfter) {
|
||||
const card = viewport.querySelector('.motion-card');
|
||||
if (!card) return;
|
||||
|
||||
card.className = isAfter ? 'motion-card motion-card-after' : 'motion-card motion-card-before';
|
||||
|
||||
if (isAfter) {
|
||||
card.querySelector('.motion-card-icon').textContent = '✓';
|
||||
card.querySelector('.motion-card-text').textContent = 'Order Confirmed';
|
||||
} else {
|
||||
card.querySelector('.motion-card-icon').textContent = '📦';
|
||||
card.querySelector('.motion-card-text').textContent = 'Order Placed';
|
||||
}
|
||||
}
|
||||
|
||||
// ========== TYPOGRAPHY ==========
|
||||
|
||||
function toggleTypoPairing(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.typo-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'typo-demo typo-pairing-after' : 'typo-demo typo-pairing-before';
|
||||
}
|
||||
|
||||
function toggleTypoHierarchy(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.typo-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'typo-demo typo-hierarchy-after' : 'typo-demo typo-hierarchy-before';
|
||||
}
|
||||
|
||||
// ========== INTERACTION DESIGN ==========
|
||||
|
||||
function toggleAffordance(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.int-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'int-demo int-affordance-after' : 'int-demo int-affordance-before';
|
||||
}
|
||||
|
||||
function toggleFeedback(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.int-demo');
|
||||
if (!demo) return;
|
||||
|
||||
if (isAfter) {
|
||||
demo.className = 'int-demo int-feedback-after';
|
||||
demo.innerHTML = `
|
||||
<button class="int-fb-btn int-fb-active" data-action="like">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
|
||||
</button>
|
||||
<span class="int-fb-label">Click to try!</span>
|
||||
`;
|
||||
// Re-setup interactive button
|
||||
setupInteractiveButtons();
|
||||
} else {
|
||||
demo.className = 'int-demo int-feedback-before';
|
||||
demo.innerHTML = `
|
||||
<button class="int-fb-btn int-fb-silent">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
|
||||
</button>
|
||||
<span class="int-fb-label">Click — nothing happens</span>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
// ========== COLOR & CONTRAST ==========
|
||||
|
||||
function toggleColorPalette(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.color-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'color-demo color-palette-after' : 'color-demo color-palette-before';
|
||||
}
|
||||
|
||||
function toggleColorAccent(viewport, isAfter) {
|
||||
const demo = viewport.querySelector('.color-demo');
|
||||
if (!demo) return;
|
||||
|
||||
demo.className = isAfter ? 'color-demo color-accent-after' : 'color-demo color-accent-before';
|
||||
}
|
||||
|
||||
// ========== COMMAND DEMOS ==========
|
||||
|
||||
function handleCommandDemoToggle(demoId, isAfter) {
|
||||
switch (demoId) {
|
||||
case 'command-bolder':
|
||||
handleBolderDemo(isAfter);
|
||||
break;
|
||||
case 'command-animate':
|
||||
handleAnimateDemo(isAfter);
|
||||
break;
|
||||
case 'command-normalize':
|
||||
handleNormalizeDemo(isAfter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function handleBolderDemo(isAfter) {
|
||||
const viewport = document.getElementById('command-bolder-viewport');
|
||||
if (!viewport) return;
|
||||
|
||||
if (isAfter) {
|
||||
viewport.innerHTML = `
|
||||
<div style="text-align: center; padding: var(--s-lg); max-width: 320px;">
|
||||
<div style="font-family: var(--font-display); font-size: 2.5rem; font-weight: 300; font-style: italic; margin-bottom: 12px; color: var(--c-text); line-height: 1;">Introducing Our Product</div>
|
||||
<div style="font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.15em; color: var(--c-accent); margin-bottom: 24px;">A solution for modern teams</div>
|
||||
<button style="padding: 14px 32px; background: var(--c-text); color: var(--c-paper); border: none; font-size: 0.9375rem; font-weight: 500; letter-spacing: 0.02em;">Learn More</button>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
viewport.innerHTML = `
|
||||
<div style="text-align: center; padding: var(--s-md); max-width: 280px;">
|
||||
<div style="font-size: 1.125rem; font-weight: 500; margin-bottom: 8px; color: var(--c-charcoal);">Introducing Our Product</div>
|
||||
<div style="font-size: 0.875rem; color: var(--c-ash); margin-bottom: 16px;">A solution for modern teams</div>
|
||||
<button style="padding: 8px 16px; background: var(--c-mist); color: var(--c-charcoal); border: none; border-radius: 4px; font-size: 0.875rem;">Learn More</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function handleAnimateDemo(isAfter) {
|
||||
const viewport = document.getElementById('command-animate-viewport');
|
||||
if (viewport) {
|
||||
viewport.dataset.state = isAfter ? 'after' : 'before';
|
||||
if (isAfter) {
|
||||
const page = viewport.querySelector('.motion-demo-page');
|
||||
if (page) {
|
||||
const clone = page.cloneNode(true);
|
||||
page.parentNode.replaceChild(clone, page);
|
||||
}
|
||||
// HTML swap
|
||||
if (tab.after && tab.before) {
|
||||
viewport.innerHTML = isAfter ? tab.after : tab.before;
|
||||
|
||||
// Run after-render callback if exists
|
||||
if (isAfter && tab.onAfterRender) {
|
||||
tab.onAfterRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleNormalizeDemo(isAfter) {
|
||||
const viewport = document.getElementById('command-normalize-viewport');
|
||||
/**
|
||||
* Handle command demo toggle
|
||||
*/
|
||||
function handleCommandDemoToggle(demoId, isAfter) {
|
||||
// Extract command ID from demoId (e.g., "command-normalize" -> "normalize")
|
||||
const commandId = demoId.replace('command-', '');
|
||||
const demo = getCommandDemo(commandId);
|
||||
|
||||
if (!demo) return;
|
||||
|
||||
const viewport = document.getElementById(`${demoId}-viewport`);
|
||||
if (!viewport) return;
|
||||
|
||||
if (isAfter) {
|
||||
viewport.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; gap: var(--s-sm); width: 100%; max-width: 260px;">
|
||||
<div style="padding: var(--s-md); background: var(--c-bg); border-radius: 4px; border-left: 2px solid var(--c-accent);">
|
||||
<div style="font-size: 0.9375rem; font-weight: 600; margin-bottom: 4px; color: var(--c-text);">Card One</div>
|
||||
<div style="font-size: 0.8125rem; color: var(--c-ash);">Consistent description text</div>
|
||||
</div>
|
||||
<div style="padding: var(--s-md); background: var(--c-bg); border-radius: 4px; border-left: 2px solid var(--c-accent);">
|
||||
<div style="font-size: 0.9375rem; font-weight: 600; margin-bottom: 4px; color: var(--c-text);">Card Two</div>
|
||||
<div style="font-size: 0.8125rem; color: var(--c-ash);">Same spacing and styles</div>
|
||||
</div>
|
||||
<div style="padding: var(--s-md); background: var(--c-bg); border-radius: 4px; border-left: 2px solid var(--c-accent);">
|
||||
<div style="font-size: 0.9375rem; font-weight: 600; margin-bottom: 4px; color: var(--c-text);">Card Three</div>
|
||||
<div style="font-size: 0.8125rem; color: var(--c-ash);">Unified design system</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
viewport.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 260px;">
|
||||
<div style="padding: 12px 16px; background: #f0f0f0; border-radius: 6px;">
|
||||
<div style="font-size: 14px; font-weight: 600; margin-bottom: 4px;">Card One</div>
|
||||
<div style="font-size: 13px; color: #888;">Some description text here</div>
|
||||
</div>
|
||||
<div style="padding: 18px 12px; background: #e8e8e8; border-radius: 12px;">
|
||||
<div style="font-size: 16px; font-weight: 500; margin-bottom: 8px;">Card Two</div>
|
||||
<div style="font-size: 14px; color: #666;">Different spacing and styles</div>
|
||||
</div>
|
||||
<div style="padding: 10px 20px; background: #f5f5f5; border-radius: 4px;">
|
||||
<div style="font-size: 15px; font-weight: 700; margin-bottom: 2px;">Card Three</div>
|
||||
<div style="font-size: 12px; color: #999;">Yet another variation</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
viewport.dataset.state = isAfter ? 'after' : 'before';
|
||||
|
||||
// Check for custom toggle handler
|
||||
if (demo.onToggle) {
|
||||
demo.onToggle(viewport, isAfter);
|
||||
return;
|
||||
}
|
||||
|
||||
// HTML swap
|
||||
if (demo.after && demo.before) {
|
||||
viewport.innerHTML = isAfter ? demo.after : demo.before;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Animate command demo - shows static page becoming choreographed
|
||||
export default {
|
||||
id: 'animate',
|
||||
caption: 'Static page → Choreographed page load',
|
||||
|
||||
// This demo uses CSS animations triggered by data-state attribute
|
||||
// The before/after states are the same HTML, animation is CSS-driven
|
||||
before: `
|
||||
<div class="motion-demo-page" style="opacity: 1;">
|
||||
<div class="motion-demo-page-hero" style="opacity: 1; transform: none;">Hero</div>
|
||||
<div class="motion-demo-page-content">
|
||||
<div class="motion-demo-page-heading" style="opacity: 1; transform: none;"></div>
|
||||
<div class="motion-demo-page-text" style="opacity: 1; transform: none;"></div>
|
||||
<div class="motion-demo-page-text" style="opacity: 1; transform: none;"></div>
|
||||
<div class="motion-demo-page-text" style="opacity: 1; transform: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
after: null, // Uses CSS animation, no HTML change needed
|
||||
|
||||
// Custom toggle handler for animation re-triggering
|
||||
onToggle: (viewport, isAfter) => {
|
||||
viewport.dataset.state = isAfter ? 'after' : 'before';
|
||||
if (isAfter) {
|
||||
// Re-trigger animation by cloning the element
|
||||
const page = viewport.querySelector('.motion-demo-page');
|
||||
if (page) {
|
||||
const clone = page.cloneNode(true);
|
||||
page.parentNode.replaceChild(clone, page);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
viewportClass: 'demo-viewport-dark'
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
// Bolder command demo - shows timid design becoming bold and confident
|
||||
export default {
|
||||
id: 'bolder',
|
||||
caption: 'Timid design → Bold, confident design',
|
||||
|
||||
before: `
|
||||
<div style="text-align: center; padding: var(--spacing-md); max-width: 280px;">
|
||||
<div style="font-size: 1.125rem; font-weight: 500; margin-bottom: 8px; color: var(--color-charcoal);">Introducing Our Product</div>
|
||||
<div style="font-size: 0.875rem; color: var(--color-ash); margin-bottom: 16px;">A solution for modern teams</div>
|
||||
<button style="padding: 8px 16px; background: var(--color-mist); color: var(--color-charcoal); border: none; border-radius: 4px; font-size: 0.875rem;">Learn More</button>
|
||||
</div>
|
||||
`,
|
||||
|
||||
after: `
|
||||
<div style="text-align: center; padding: var(--spacing-lg); max-width: 320px;">
|
||||
<div style="font-family: var(--font-display); font-size: 2.5rem; font-weight: 300; font-style: italic; margin-bottom: 12px; color: var(--color-ink); line-height: 1;">Introducing Our Product</div>
|
||||
<div style="font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.15em; color: var(--color-accent); margin-bottom: 24px;">A solution for modern teams</div>
|
||||
<button style="padding: 14px 32px; background: var(--color-ink); color: var(--color-paper); border: none; font-size: 0.9375rem; font-weight: 500; letter-spacing: 0.02em;">Learn More</button>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
// Command demos registry
|
||||
|
||||
import animate from "./animate.js";
|
||||
import bolder from "./bolder.js";
|
||||
import normalize from "./normalize.js";
|
||||
|
||||
export const commandDemos = {
|
||||
normalize,
|
||||
bolder,
|
||||
animate,
|
||||
};
|
||||
|
||||
export function getCommandDemo(commandId) {
|
||||
return commandDemos[commandId] || null;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Normalize command demo - shows inconsistent styles becoming systematic
|
||||
export default {
|
||||
id: 'normalize',
|
||||
caption: 'Inconsistent styles → Systematic design tokens',
|
||||
|
||||
before: `
|
||||
<div style="display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 260px;">
|
||||
<div style="padding: 12px 16px; background: #f0f0f0; border-radius: 6px;">
|
||||
<div style="font-size: 14px; font-weight: 600; margin-bottom: 4px;">Card One</div>
|
||||
<div style="font-size: 13px; color: #888;">Some description text here</div>
|
||||
</div>
|
||||
<div style="padding: 18px 12px; background: #e8e8e8; border-radius: 12px;">
|
||||
<div style="font-size: 16px; font-weight: 500; margin-bottom: 8px;">Card Two</div>
|
||||
<div style="font-size: 14px; color: #666;">Different spacing and styles</div>
|
||||
</div>
|
||||
<div style="padding: 10px 20px; background: #f5f5f5; border-radius: 4px;">
|
||||
<div style="font-size: 15px; font-weight: 700; margin-bottom: 2px;">Card Three</div>
|
||||
<div style="font-size: 12px; color: #999;">Yet another variation</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
after: `
|
||||
<div style="display: flex; flex-direction: column; gap: var(--spacing-sm); width: 100%; max-width: 260px;">
|
||||
<div style="padding: var(--spacing-md); background: var(--color-paper); border: 1px solid var(--color-mist); border-radius: 6px;">
|
||||
<div style="font-size: 0.9375rem; font-weight: 600; margin-bottom: 4px; color: var(--color-ink);">Card One</div>
|
||||
<div style="font-size: 0.8125rem; color: var(--color-ash);">Consistent description text</div>
|
||||
</div>
|
||||
<div style="padding: var(--spacing-md); background: var(--color-paper); border: 1px solid var(--color-mist); border-radius: 6px;">
|
||||
<div style="font-size: 0.9375rem; font-weight: 600; margin-bottom: 4px; color: var(--color-ink);">Card Two</div>
|
||||
<div style="font-size: 0.8125rem; color: var(--color-ash);">Same spacing and styles</div>
|
||||
</div>
|
||||
<div style="padding: var(--spacing-md); background: var(--color-paper); border: 1px solid var(--color-mist); border-radius: 6px;">
|
||||
<div style="font-size: 0.9375rem; font-weight: 600; margin-bottom: 4px; color: var(--color-ink);">Card Three</div>
|
||||
<div style="font-size: 0.8125rem; color: var(--color-ash);">Unified design system</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
// Main demos registry - exports all demos
|
||||
export { commandDemos, getCommandDemo } from "./commands/index.js";
|
||||
export { getSkillDemo, skillDemos } from "./skills/index.js";
|
||||
@@ -0,0 +1,65 @@
|
||||
// Color and Contrast skill demos
|
||||
export default {
|
||||
id: 'color-and-contrast',
|
||||
tabs: [
|
||||
{
|
||||
id: 'palette',
|
||||
label: 'Color Harmony',
|
||||
caption: 'Clashing colors vs harmonious palette',
|
||||
beforeClass: 'color-demo color-palette-before',
|
||||
afterClass: 'color-demo color-palette-after',
|
||||
before: `
|
||||
<div class="color-demo color-palette-before">
|
||||
<div class="color-swatch swatch-1"></div>
|
||||
<div class="color-swatch swatch-2"></div>
|
||||
<div class="color-swatch swatch-3"></div>
|
||||
<div class="color-swatch swatch-4"></div>
|
||||
<div class="color-swatch swatch-5"></div>
|
||||
<div class="color-card">
|
||||
<span class="card-title">Title</span>
|
||||
<span class="card-subtitle">Subtitle</span>
|
||||
<button class="card-btn">Action</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
},
|
||||
{
|
||||
id: 'accent',
|
||||
label: 'Strategic Accent',
|
||||
caption: 'Monochrome monotony vs strategic accent',
|
||||
beforeClass: 'color-demo color-accent-before',
|
||||
afterClass: 'color-demo color-accent-after',
|
||||
before: `
|
||||
<div class="color-demo color-accent-before">
|
||||
<div class="color-accent-card">
|
||||
<div class="color-accent-title">Premium Plan</div>
|
||||
<div class="color-accent-text">Unlock all features and get priority support.</div>
|
||||
<button class="color-accent-btn">Upgrade Now</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
},
|
||||
{
|
||||
id: 'contrast',
|
||||
label: 'Contrast Ratios',
|
||||
caption: 'Accessibility failures vs WCAG compliance',
|
||||
hasToggle: false, // Static comparison
|
||||
before: `
|
||||
<div class="color-demo color-contrast-static">
|
||||
<div class="contrast-example contrast-fail">
|
||||
<span class="contrast-badge">Fails WCAG</span>
|
||||
<div class="contrast-text">Hard to Read</div>
|
||||
<div class="contrast-ratio">2.5:1</div>
|
||||
</div>
|
||||
<div class="contrast-example contrast-pass">
|
||||
<span class="contrast-badge">Passes AAA</span>
|
||||
<div class="contrast-text">Easy to Read</div>
|
||||
<div class="contrast-ratio">12.6:1</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
// Skill demos registry
|
||||
|
||||
import colorAndContrast from "./color-and-contrast.js";
|
||||
import interactionDesign from "./interaction-design.js";
|
||||
import motionDesign from "./motion-design.js";
|
||||
import responsiveDesign from "./responsive-design.js";
|
||||
import spatialDesign from "./spatial-design.js";
|
||||
import typography from "./typography.js";
|
||||
import uxWriting from "./ux-writing.js";
|
||||
|
||||
export const skillDemos = {
|
||||
"ux-writing": uxWriting,
|
||||
"spatial-design": spatialDesign,
|
||||
"motion-design": motionDesign,
|
||||
typography: typography,
|
||||
"interaction-design": interactionDesign,
|
||||
"color-and-contrast": colorAndContrast,
|
||||
"responsive-design": responsiveDesign,
|
||||
};
|
||||
|
||||
export function getSkillDemo(skillId) {
|
||||
return skillDemos[skillId] || null;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Interaction Design skill demos
|
||||
export default {
|
||||
id: 'interaction-design',
|
||||
tabs: [
|
||||
{
|
||||
id: 'states',
|
||||
label: 'Button States',
|
||||
caption: 'Missing states vs complete interaction feedback',
|
||||
// This demo shows both states side-by-side, no toggle needed
|
||||
hasToggle: false,
|
||||
before: `
|
||||
<div class="int-demo int-states-demo">
|
||||
<div class="int-state-row">
|
||||
<span class="int-state-label">Poor</span>
|
||||
<button class="int-btn int-btn-poor">Click Me</button>
|
||||
</div>
|
||||
<div class="int-state-row">
|
||||
<span class="int-state-label">Good</span>
|
||||
<button class="int-btn int-btn-good">Click Me</button>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'affordance',
|
||||
label: 'Affordances',
|
||||
caption: 'Unclear actions vs obvious clickability',
|
||||
beforeClass: 'int-demo int-affordance-before',
|
||||
afterClass: 'int-demo int-affordance-after',
|
||||
before: `
|
||||
<div class="int-demo int-affordance-before">
|
||||
<div class="int-aff-item int-aff-poor">
|
||||
<span>Learn more</span>
|
||||
</div>
|
||||
<div class="int-aff-item int-aff-poor">
|
||||
<span>Settings</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
},
|
||||
{
|
||||
id: 'feedback',
|
||||
label: 'Feedback',
|
||||
caption: 'Silent actions vs immediate confirmation',
|
||||
before: `
|
||||
<div class="int-demo int-feedback-before">
|
||||
<button class="int-fb-btn int-fb-silent">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
|
||||
</button>
|
||||
<span class="int-fb-label">Click — nothing happens</span>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="int-demo int-feedback-after">
|
||||
<button class="int-fb-btn int-fb-active" data-action="like">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
|
||||
</button>
|
||||
<span class="int-fb-label">Click to try!</span>
|
||||
</div>
|
||||
`,
|
||||
onAfterRender: () => {
|
||||
// Setup interactive like button
|
||||
document.querySelectorAll('.int-fb-active[data-action="like"]').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
btn.classList.toggle('liked');
|
||||
const label = btn.nextElementSibling;
|
||||
if (label) {
|
||||
label.textContent = btn.classList.contains('liked') ? 'Liked!' : 'Click to try!';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
// Motion Design skill demos
|
||||
export default {
|
||||
id: 'motion-design',
|
||||
tabs: [
|
||||
{
|
||||
id: 'stagger',
|
||||
label: 'Staggered Reveal',
|
||||
caption: 'Instant appearance vs orchestrated reveal',
|
||||
before: `
|
||||
<div class="motion-demo motion-stagger-demo">
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Dashboard</div>
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Analytics</div>
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Settings</div>
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Profile</div>
|
||||
</div>
|
||||
`,
|
||||
after: null, // CSS animation triggered by data-state
|
||||
onToggle: (viewport, isAfter) => {
|
||||
if (isAfter) {
|
||||
// Re-trigger animation by cloning elements
|
||||
const items = viewport.querySelectorAll('.motion-list-item');
|
||||
items.forEach(item => {
|
||||
const clone = item.cloneNode(true);
|
||||
item.parentNode.replaceChild(clone, item);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'micro',
|
||||
label: 'Micro-interactions',
|
||||
caption: 'Static button vs responsive feedback',
|
||||
before: `
|
||||
<div class="motion-demo motion-micro-demo">
|
||||
<button class="motion-btn motion-btn-before">Add to Cart</button>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="motion-demo motion-micro-demo">
|
||||
<button class="motion-btn motion-btn-after">Add to Cart</button>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'transition',
|
||||
label: 'State Changes',
|
||||
caption: 'Jarring change vs smooth transition',
|
||||
before: `
|
||||
<div class="motion-demo motion-transition-demo">
|
||||
<div class="motion-card motion-card-before">
|
||||
<div class="motion-card-icon">📦</div>
|
||||
<div class="motion-card-text">Order Placed</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="motion-demo motion-transition-demo">
|
||||
<div class="motion-card motion-card-after">
|
||||
<div class="motion-card-icon">✓</div>
|
||||
<div class="motion-card-text">Order Confirmed</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
// Responsive Design skill demos
|
||||
export default {
|
||||
id: 'responsive-design',
|
||||
tabs: [
|
||||
{
|
||||
id: 'touch',
|
||||
label: 'Touch Targets',
|
||||
caption: 'Tiny targets vs accessible touch areas',
|
||||
hasToggle: false, // Static comparison
|
||||
before: `
|
||||
<div class="resp-demo resp-touch-demo">
|
||||
<div class="resp-touch-row">
|
||||
<span class="resp-label">Too Small</span>
|
||||
<div class="resp-touch-targets resp-touch-bad">
|
||||
<button>×</button>
|
||||
<button>−</button>
|
||||
<button>+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resp-touch-row">
|
||||
<span class="resp-label">Accessible</span>
|
||||
<div class="resp-touch-targets resp-touch-good">
|
||||
<button>×</button>
|
||||
<button>−</button>
|
||||
<button>+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'fluid',
|
||||
label: 'Fluid Layout',
|
||||
caption: 'Fixed breakage vs fluid adaptation',
|
||||
hasToggle: false, // Static comparison
|
||||
before: `
|
||||
<div class="resp-demo resp-fluid-demo">
|
||||
<div class="resp-fluid-container">
|
||||
<div class="resp-fluid-fixed">
|
||||
<span>Fixed 400px</span>
|
||||
<div class="resp-fluid-bar" style="width: 400px; max-width: 100%;"></div>
|
||||
</div>
|
||||
<div class="resp-fluid-adaptive">
|
||||
<span>Fluid 80%</span>
|
||||
<div class="resp-fluid-bar" style="width: 80%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'adapt',
|
||||
label: 'Adaptive Content',
|
||||
caption: 'Same layout vs optimized for context',
|
||||
hasToggle: false, // Static comparison
|
||||
before: `
|
||||
<div class="resp-demo resp-adapt-demo">
|
||||
<div class="resp-device resp-device-mobile">
|
||||
<div class="resp-device-screen">
|
||||
<div class="resp-block resp-header"></div>
|
||||
<div class="resp-block resp-content"></div>
|
||||
</div>
|
||||
<span>Mobile</span>
|
||||
</div>
|
||||
<div class="resp-device resp-device-tablet">
|
||||
<div class="resp-device-screen">
|
||||
<div class="resp-block resp-header"></div>
|
||||
<div class="resp-block-row">
|
||||
<div class="resp-block resp-content"></div>
|
||||
<div class="resp-block resp-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span>Tablet</span>
|
||||
</div>
|
||||
<div class="resp-device resp-device-desktop">
|
||||
<div class="resp-device-screen">
|
||||
<div class="resp-block-row">
|
||||
<div class="resp-block resp-sidebar"></div>
|
||||
<div class="resp-block resp-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span>Desktop</span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
// Spatial Design skill demos
|
||||
export default {
|
||||
id: 'spatial-design',
|
||||
tabs: [
|
||||
{
|
||||
id: 'grid',
|
||||
label: 'Grid Systems',
|
||||
caption: 'Chaotic placement vs intentional grid alignment',
|
||||
before: `
|
||||
<div class="spatial-demo spatial-grid-before">
|
||||
<div class="spatial-card-item" style="width: 45%;">Card One</div>
|
||||
<div class="spatial-card-item" style="width: 30%;">Card Two</div>
|
||||
<div class="spatial-card-item" style="width: 55%;">Card Three</div>
|
||||
<div class="spatial-card-item" style="width: 25%;">Card Four</div>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="spatial-demo spatial-grid-after">
|
||||
<div class="spatial-card-item">Card One</div>
|
||||
<div class="spatial-card-item">Card Two</div>
|
||||
<div class="spatial-card-item">Card Three</div>
|
||||
<div class="spatial-card-item">Card Four</div>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'hierarchy',
|
||||
label: 'Visual Weight',
|
||||
caption: 'Equal weight vs clear visual priority',
|
||||
beforeClass: 'spatial-demo spatial-hierarchy-before',
|
||||
afterClass: 'spatial-demo spatial-hierarchy-after',
|
||||
before: `
|
||||
<div class="spatial-demo spatial-hierarchy-before">
|
||||
<div class="spatial-h-title">Welcome Back</div>
|
||||
<div class="spatial-h-subtitle">Dashboard</div>
|
||||
<div class="spatial-h-cta">View Reports</div>
|
||||
<div class="spatial-h-link">Settings</div>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
},
|
||||
{
|
||||
id: 'whitespace',
|
||||
label: 'Breathing Room',
|
||||
caption: 'Cramped elements vs comfortable spacing',
|
||||
beforeClass: 'spatial-demo spatial-whitespace-before',
|
||||
afterClass: 'spatial-demo spatial-whitespace-after',
|
||||
before: `
|
||||
<div class="spatial-demo spatial-whitespace-before">
|
||||
<div class="spatial-ws-title">Premium Plan</div>
|
||||
<div class="spatial-ws-price">$29/mo</div>
|
||||
<div class="spatial-ws-features">Unlimited projects • Priority support • Advanced analytics</div>
|
||||
<button class="spatial-ws-btn">Upgrade Now</button>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
// Typography skill demos
|
||||
export default {
|
||||
id: 'typography',
|
||||
tabs: [
|
||||
{
|
||||
id: 'pairing',
|
||||
label: 'Font Pairing',
|
||||
caption: 'Generic system fonts vs distinctive pairing',
|
||||
beforeClass: 'typo-demo typo-pairing-before',
|
||||
afterClass: 'typo-demo typo-pairing-after',
|
||||
before: `
|
||||
<div class="typo-demo typo-pairing-before">
|
||||
<div class="typo-heading">Welcome to the Future</div>
|
||||
<div class="typo-body">Experience innovation like never before with our cutting-edge platform designed for modern teams.</div>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
},
|
||||
{
|
||||
id: 'hierarchy',
|
||||
label: 'Scale & Hierarchy',
|
||||
caption: 'Flat sizing vs dramatic scale contrast',
|
||||
beforeClass: 'typo-demo typo-hierarchy-before',
|
||||
afterClass: 'typo-demo typo-hierarchy-after',
|
||||
before: `
|
||||
<div class="typo-demo typo-hierarchy-before">
|
||||
<div class="typo-h1">Article Title</div>
|
||||
<div class="typo-meta">Published January 2025</div>
|
||||
<div class="typo-p">This is the body text of the article containing the main content and ideas.</div>
|
||||
</div>
|
||||
`,
|
||||
after: null // Uses CSS class toggle
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
// UX Writing skill demos
|
||||
export default {
|
||||
id: 'ux-writing',
|
||||
tabs: [
|
||||
{
|
||||
id: 'errors',
|
||||
label: 'Error Messages',
|
||||
caption: 'Technical jargon vs human, actionable guidance',
|
||||
before: `
|
||||
<div class="uxw-demo uxw-error-before">
|
||||
<div class="uxw-error-icon">⚠</div>
|
||||
<div class="uxw-error-title">Error 403</div>
|
||||
<div class="uxw-error-text">Access denied. Authentication failure occurred.</div>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="uxw-demo uxw-error-after">
|
||||
<div class="uxw-error-icon">🔐</div>
|
||||
<div class="uxw-error-title">You don't have access</div>
|
||||
<div class="uxw-error-text">Your session may have expired. Sign in again to continue.</div>
|
||||
<div class="uxw-error-action">Sign in →</div>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'buttons',
|
||||
label: 'Button Labels',
|
||||
caption: 'Vague labels vs clear, specific actions',
|
||||
before: `
|
||||
<div class="uxw-demo uxw-buttons-before">
|
||||
<div class="uxw-button-context">Delete account permanently?</div>
|
||||
<div class="uxw-button-row">
|
||||
<button class="uxw-btn uxw-btn-primary">Submit</button>
|
||||
<button class="uxw-btn uxw-btn-secondary">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="uxw-demo uxw-buttons-after">
|
||||
<div class="uxw-button-context">Delete account permanently?</div>
|
||||
<div class="uxw-button-row">
|
||||
<button class="uxw-btn uxw-btn-danger">Delete My Account</button>
|
||||
<button class="uxw-btn uxw-btn-secondary">Keep Account</button>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
},
|
||||
{
|
||||
id: 'empty',
|
||||
label: 'Empty States',
|
||||
caption: 'Blank nothing vs helpful, encouraging guidance',
|
||||
before: `
|
||||
<div class="uxw-demo uxw-empty-before">
|
||||
<div class="uxw-empty-icon">📁</div>
|
||||
<div class="uxw-empty-title">No items</div>
|
||||
</div>
|
||||
`,
|
||||
after: `
|
||||
<div class="uxw-demo uxw-empty-after">
|
||||
<div class="uxw-empty-icon">📝</div>
|
||||
<div class="uxw-empty-title">No projects yet</div>
|
||||
<div class="uxw-empty-text">Create your first project to get started.</div>
|
||||
<div class="uxw-empty-action"><button class="uxw-btn uxw-btn-primary">Create Project</button></div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -1,386 +0,0 @@
|
||||
// ============================================
|
||||
// SKILL DEMOS - Interactive before/after demonstrations
|
||||
// Each skill has multiple demos selectable via tabs
|
||||
// ============================================
|
||||
|
||||
// Demo definitions for each skill
|
||||
const skillDemoDefinitions = {
|
||||
'ux-writing': [
|
||||
{ id: 'errors', label: 'Error Messages', demo: 'uxwriting-error' },
|
||||
{ id: 'buttons', label: 'Button Labels', demo: 'uxwriting-buttons' },
|
||||
{ id: 'empty', label: 'Empty States', demo: 'uxwriting-empty' }
|
||||
],
|
||||
'spatial-design': [
|
||||
{ id: 'grid', label: 'Grid Systems', demo: 'spatial-grid' },
|
||||
{ id: 'hierarchy', label: 'Visual Weight', demo: 'spatial-hierarchy' },
|
||||
{ id: 'whitespace', label: 'Breathing Room', demo: 'spatial-whitespace' }
|
||||
],
|
||||
'motion-design': [
|
||||
{ id: 'stagger', label: 'Staggered Reveal', demo: 'motion-stagger' },
|
||||
{ id: 'micro', label: 'Micro-interactions', demo: 'motion-micro' },
|
||||
{ id: 'transition', label: 'State Changes', demo: 'motion-transition' }
|
||||
],
|
||||
'typography': [
|
||||
{ id: 'pairing', label: 'Font Pairing', demo: 'typography-pairing' },
|
||||
{ id: 'hierarchy', label: 'Scale & Hierarchy', demo: 'typography-hierarchy' }
|
||||
],
|
||||
'interaction-design': [
|
||||
{ id: 'states', label: 'Button States', demo: 'interaction-states' },
|
||||
{ id: 'affordance', label: 'Affordances', demo: 'interaction-affordance' },
|
||||
{ id: 'feedback', label: 'Feedback', demo: 'interaction-feedback' }
|
||||
],
|
||||
'color-and-contrast': [
|
||||
{ id: 'palette', label: 'Color Harmony', demo: 'color-palette' },
|
||||
{ id: 'accent', label: 'Strategic Accent', demo: 'color-accent' },
|
||||
{ id: 'contrast', label: 'Contrast Ratios', demo: 'color-contrast' }
|
||||
],
|
||||
'responsive-design': [
|
||||
{ id: 'touch', label: 'Touch Targets', demo: 'responsive-touch' },
|
||||
{ id: 'fluid', label: 'Fluid Layout', demo: 'responsive-fluid' },
|
||||
{ id: 'adapt', label: 'Adaptive Content', demo: 'responsive-adapt' }
|
||||
]
|
||||
};
|
||||
|
||||
export function renderSkillDemo(skillId) {
|
||||
const demos = skillDemoDefinitions[skillId];
|
||||
if (!demos || demos.length === 0) {
|
||||
return renderGenericDemo(skillId);
|
||||
}
|
||||
|
||||
const showTabs = demos.length > 1;
|
||||
|
||||
const tabs = showTabs ? demos.map((d, i) => `
|
||||
<button class="demo-tab ${i === 0 ? 'active' : ''}" data-demo-tab="${d.id}" data-skill="${skillId}">
|
||||
${d.label}
|
||||
</button>
|
||||
`).join('') : '';
|
||||
|
||||
const demoContents = demos.map((d, i) => `
|
||||
<div class="demo-panel ${i === 0 ? 'active' : ''}" data-demo-panel="${d.id}">
|
||||
${renderDemoContent(skillId, d)}
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
return `
|
||||
<div class="demo-tabbed-container">
|
||||
${showTabs ? `<div class="demo-tabs">${tabs}</div>` : ''}
|
||||
<div class="demo-panels">
|
||||
${demoContents}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderDemoContent(_skillId, demoConfig) {
|
||||
const demoId = demoConfig.demo;
|
||||
const noToggle = ['color-contrast', 'responsive-touch', 'responsive-fluid', 'responsive-adapt'];
|
||||
const hasToggle = !noToggle.includes(demoId);
|
||||
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
${hasToggle ? `
|
||||
<div class="demo-toggle">
|
||||
<span class="demo-toggle-label active">Before</span>
|
||||
<div class="demo-toggle-switch" data-demo="${demoId}"></div>
|
||||
<span class="demo-toggle-label">After</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="demo-viewport" data-state="before" id="${demoId}-viewport">
|
||||
${getDemoInitialContent(demoId)}
|
||||
</div>
|
||||
<div class="demo-caption">${getDemoCaption(demoId)}</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function getDemoCaption(demoId) {
|
||||
const captions = {
|
||||
// UX Writing
|
||||
'uxwriting-error': 'Technical jargon vs human, actionable guidance',
|
||||
'uxwriting-buttons': 'Vague labels vs clear, specific actions',
|
||||
'uxwriting-empty': 'Blank nothing vs helpful, encouraging guidance',
|
||||
// Spatial Design
|
||||
'spatial-grid': 'Chaotic placement vs intentional grid alignment',
|
||||
'spatial-hierarchy': 'Equal weight vs clear visual priority',
|
||||
'spatial-whitespace': 'Cramped elements vs comfortable spacing',
|
||||
// Motion Design
|
||||
'motion-stagger': 'Instant appearance vs orchestrated reveal',
|
||||
'motion-micro': 'Static button vs responsive feedback',
|
||||
'motion-transition': 'Jarring change vs smooth transition',
|
||||
// Typography
|
||||
'typography-pairing': 'Generic system fonts vs distinctive pairing',
|
||||
'typography-hierarchy': 'Flat sizing vs dramatic scale contrast',
|
||||
// Interaction Design
|
||||
'interaction-states': 'Missing states vs complete interaction feedback',
|
||||
'interaction-affordance': 'Unclear actions vs obvious clickability',
|
||||
'interaction-feedback': 'Silent actions vs immediate confirmation',
|
||||
// Color & Contrast
|
||||
'color-palette': 'Clashing colors vs harmonious palette',
|
||||
'color-accent': 'Monochrome monotony vs strategic accent',
|
||||
'color-contrast': 'Accessibility failures vs WCAG compliance',
|
||||
// Responsive Design
|
||||
'responsive-touch': 'Tiny targets vs accessible touch areas',
|
||||
'responsive-fluid': 'Fixed breakage vs fluid adaptation',
|
||||
'responsive-adapt': 'Same layout vs optimized for context'
|
||||
};
|
||||
return captions[demoId] || '';
|
||||
}
|
||||
|
||||
function getDemoInitialContent(demoId) {
|
||||
const contents = {
|
||||
// ========== UX WRITING ==========
|
||||
'uxwriting-error': `
|
||||
<div class="uxw-demo uxw-error-before">
|
||||
<div class="uxw-error-icon">⚠</div>
|
||||
<div class="uxw-error-title">Error 403</div>
|
||||
<div class="uxw-error-text">Access denied. Authentication failure occurred.</div>
|
||||
</div>
|
||||
`,
|
||||
'uxwriting-buttons': `
|
||||
<div class="uxw-demo uxw-buttons-before">
|
||||
<div class="uxw-button-row">
|
||||
<button class="uxw-btn uxw-btn-primary">Submit</button>
|
||||
<button class="uxw-btn uxw-btn-secondary">Cancel</button>
|
||||
</div>
|
||||
<div class="uxw-button-context">Delete account permanently?</div>
|
||||
</div>
|
||||
`,
|
||||
'uxwriting-empty': `
|
||||
<div class="uxw-demo uxw-empty-before">
|
||||
<div class="uxw-empty-icon">📁</div>
|
||||
<div class="uxw-empty-title">No items</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
// ========== SPATIAL DESIGN ==========
|
||||
'spatial-grid': `
|
||||
<div class="spatial-demo spatial-grid-before">
|
||||
<div class="spatial-card-item" style="width: 45%;">Card One</div>
|
||||
<div class="spatial-card-item" style="width: 30%;">Card Two</div>
|
||||
<div class="spatial-card-item" style="width: 55%;">Card Three</div>
|
||||
<div class="spatial-card-item" style="width: 25%;">Card Four</div>
|
||||
</div>
|
||||
`,
|
||||
'spatial-hierarchy': `
|
||||
<div class="spatial-demo spatial-hierarchy-before">
|
||||
<div class="spatial-h-title">Welcome Back</div>
|
||||
<div class="spatial-h-subtitle">Dashboard</div>
|
||||
<div class="spatial-h-cta">View Reports</div>
|
||||
<div class="spatial-h-link">Settings</div>
|
||||
</div>
|
||||
`,
|
||||
'spatial-whitespace': `
|
||||
<div class="spatial-demo spatial-whitespace-before">
|
||||
<div class="spatial-ws-title">Premium Plan</div>
|
||||
<div class="spatial-ws-price">$29/mo</div>
|
||||
<div class="spatial-ws-features">Unlimited projects • Priority support • Advanced analytics</div>
|
||||
<button class="spatial-ws-btn">Upgrade Now</button>
|
||||
</div>
|
||||
`,
|
||||
|
||||
// ========== MOTION DESIGN ==========
|
||||
'motion-stagger': `
|
||||
<div class="motion-demo motion-stagger-demo">
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Dashboard</div>
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Analytics</div>
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Settings</div>
|
||||
<div class="motion-list-item"><span class="motion-dot"></span>Profile</div>
|
||||
</div>
|
||||
`,
|
||||
'motion-micro': `
|
||||
<div class="motion-demo motion-micro-demo">
|
||||
<button class="motion-btn motion-btn-before">Add to Cart</button>
|
||||
</div>
|
||||
`,
|
||||
'motion-transition': `
|
||||
<div class="motion-demo motion-transition-demo">
|
||||
<div class="motion-card motion-card-before">
|
||||
<div class="motion-card-icon">📦</div>
|
||||
<div class="motion-card-text">Order Placed</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
// ========== TYPOGRAPHY ==========
|
||||
'typography-pairing': `
|
||||
<div class="typo-demo typo-pairing-before">
|
||||
<div class="typo-heading">Welcome to the Future</div>
|
||||
<div class="typo-body">Experience innovation like never before with our cutting-edge platform designed for modern teams.</div>
|
||||
</div>
|
||||
`,
|
||||
'typography-hierarchy': `
|
||||
<div class="typo-demo typo-hierarchy-before">
|
||||
<div class="typo-h1">Article Title</div>
|
||||
<div class="typo-meta">Published January 2025</div>
|
||||
<div class="typo-p">This is the body text of the article containing the main content and ideas.</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
// ========== INTERACTION DESIGN ==========
|
||||
'interaction-states': `
|
||||
<div class="int-demo int-states-demo">
|
||||
<div class="int-state-row">
|
||||
<span class="int-state-label">Poor</span>
|
||||
<button class="int-btn int-btn-poor">Click Me</button>
|
||||
</div>
|
||||
<div class="int-state-row">
|
||||
<span class="int-state-label">Good</span>
|
||||
<button class="int-btn int-btn-good">Click Me</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'interaction-affordance': `
|
||||
<div class="int-demo int-affordance-before">
|
||||
<div class="int-aff-item int-aff-poor">
|
||||
<span>Learn more</span>
|
||||
</div>
|
||||
<div class="int-aff-item int-aff-poor">
|
||||
<span>Settings</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'interaction-feedback': `
|
||||
<div class="int-demo int-feedback-before">
|
||||
<button class="int-fb-btn int-fb-silent">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
|
||||
</button>
|
||||
<span class="int-fb-label">Click — nothing happens</span>
|
||||
</div>
|
||||
`,
|
||||
|
||||
// ========== COLOR & CONTRAST ==========
|
||||
'color-palette': `
|
||||
<div class="color-demo color-palette-before">
|
||||
<div class="color-swatch swatch-1"></div>
|
||||
<div class="color-swatch swatch-2"></div>
|
||||
<div class="color-swatch swatch-3"></div>
|
||||
<div class="color-swatch swatch-4"></div>
|
||||
<div class="color-swatch swatch-5"></div>
|
||||
<div class="color-card">
|
||||
<span class="card-title">Title</span>
|
||||
<span class="card-subtitle">Subtitle</span>
|
||||
<button class="card-btn">Action</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'color-accent': `
|
||||
<div class="color-demo color-accent-before">
|
||||
<div class="color-accent-card">
|
||||
<div class="color-accent-title">Premium Plan</div>
|
||||
<div class="color-accent-text">Unlock all features and get priority support.</div>
|
||||
<button class="color-accent-btn">Upgrade Now</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'color-contrast': `
|
||||
<div class="color-demo color-contrast-static">
|
||||
<div class="contrast-example contrast-fail">
|
||||
<span class="contrast-badge">Fails WCAG</span>
|
||||
<div class="contrast-text">Hard to Read</div>
|
||||
<div class="contrast-ratio">2.5:1</div>
|
||||
</div>
|
||||
<div class="contrast-example contrast-pass">
|
||||
<span class="contrast-badge">Passes AAA</span>
|
||||
<div class="contrast-text">Easy to Read</div>
|
||||
<div class="contrast-ratio">12.6:1</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
// ========== RESPONSIVE DESIGN ==========
|
||||
'responsive-touch': `
|
||||
<div class="resp-demo resp-touch-demo">
|
||||
<div class="resp-touch-row">
|
||||
<span class="resp-label">Too Small</span>
|
||||
<div class="resp-touch-targets resp-touch-bad">
|
||||
<button>×</button>
|
||||
<button>−</button>
|
||||
<button>+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resp-touch-row">
|
||||
<span class="resp-label">Accessible</span>
|
||||
<div class="resp-touch-targets resp-touch-good">
|
||||
<button>×</button>
|
||||
<button>−</button>
|
||||
<button>+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'responsive-fluid': `
|
||||
<div class="resp-demo resp-fluid-demo">
|
||||
<div class="resp-fluid-container">
|
||||
<div class="resp-fluid-fixed">
|
||||
<span>Fixed 400px</span>
|
||||
<div class="resp-fluid-bar" style="width: 400px; max-width: 100%;"></div>
|
||||
</div>
|
||||
<div class="resp-fluid-adaptive">
|
||||
<span>Fluid 80%</span>
|
||||
<div class="resp-fluid-bar" style="width: 80%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
'responsive-adapt': `
|
||||
<div class="resp-demo resp-adapt-demo">
|
||||
<div class="resp-device resp-device-mobile">
|
||||
<div class="resp-device-screen">
|
||||
<div class="resp-block resp-header"></div>
|
||||
<div class="resp-block resp-content"></div>
|
||||
</div>
|
||||
<span>Mobile</span>
|
||||
</div>
|
||||
<div class="resp-device resp-device-tablet">
|
||||
<div class="resp-device-screen">
|
||||
<div class="resp-block resp-header"></div>
|
||||
<div class="resp-block-row">
|
||||
<div class="resp-block resp-content"></div>
|
||||
<div class="resp-block resp-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span>Tablet</span>
|
||||
</div>
|
||||
<div class="resp-device resp-device-desktop">
|
||||
<div class="resp-device-screen">
|
||||
<div class="resp-block-row">
|
||||
<div class="resp-block resp-sidebar"></div>
|
||||
<div class="resp-block resp-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span>Desktop</span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
return contents[demoId] || '<div style="padding: 2rem; text-align: center; color: #999;">Demo coming soon</div>';
|
||||
}
|
||||
|
||||
function renderGenericDemo(skillId) {
|
||||
return `
|
||||
<div class="demo-container">
|
||||
<div class="demo-viewport">
|
||||
<div style="text-align: center; color: var(--c-ash); padding: var(--s-xl);">
|
||||
<p>Demo for ${skillId.replace(/-/g, ' ')} coming soon</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
export function setupDemoTabs() {
|
||||
document.querySelectorAll('.demo-tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const tabId = tab.dataset.demoTab;
|
||||
const container = tab.closest('.demo-tabbed-container');
|
||||
|
||||
container.querySelectorAll('.demo-tab').forEach(t => { t.classList.remove('active'); });
|
||||
tab.classList.add('active');
|
||||
|
||||
container.querySelectorAll('.demo-panel').forEach(p => { p.classList.remove('active'); });
|
||||
container.querySelector(`[data-demo-panel="${tabId}"]`)?.classList.add('active');
|
||||
});
|
||||
});
|
||||
}
|
||||
+4
-4
@@ -2,9 +2,9 @@
|
||||
// SKILLS - Rendering and selection logic
|
||||
// ============================================
|
||||
|
||||
import { skillFocusAreas, readySkills } from "./data.js";
|
||||
import { readySkills, skillFocusAreas } from "./data.js";
|
||||
import { renderSkillDemo, setupDemoTabs } from "./demo-renderer.js";
|
||||
import { setupDemoToggles } from "./demo-toggles.js";
|
||||
import { renderSkillDemo, setupDemoTabs } from "./skill-demos.js";
|
||||
|
||||
let currentSkill = null;
|
||||
|
||||
@@ -39,9 +39,9 @@ export function renderSkillsNav(skills, onSelect) {
|
||||
nav.innerHTML = filteredSkills
|
||||
.map(
|
||||
(skill) => `
|
||||
<button class="skill-nav-item ${!isSkillReady(skill.id) ? 'coming-soon' : ''}" data-id="${skill.id}">
|
||||
<button class="skill-nav-item ${!isSkillReady(skill.id) ? "coming-soon" : ""}" data-id="${skill.id}">
|
||||
${formatSkillName(skill.id)}
|
||||
${!isSkillReady(skill.id) ? '<span class="coming-soon-badge">Soon</span>' : ''}
|
||||
${!isSkillReady(skill.id) ? '<span class="coming-soon-badge">Soon</span>' : ""}
|
||||
</button>
|
||||
`,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user