Redesign hero, add theme toggle, fix dark mode

- Remove GPU-intensive shader from hero section
- Combine hero with problem section for immediate impact
- Add before/after demo directly in first viewport
- Move "works with" logos inline with CTA
- Remove redundant "Common AI defaults" tags

- Add three-way theme toggle (light/system/dark)
- Persist theme preference to localStorage
- Position toggle in bottom-right corner

- Fix dark mode throughout:
  - Update glass terminal and source window backgrounds
  - Add CSS custom properties for framework category colors
  - Muted dark backgrounds with brighter text for cards

- Replace smooth scroll with instant jump for anchor links
- Remove Lenis smooth scroll library dependency

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-01-11 14:37:46 -08:00
co-authored by Claude Opus 4.5
parent a11df4f476
commit 6b77213f91
7 changed files with 376 additions and 430 deletions
+4 -5
View File
@@ -4,9 +4,9 @@ import {
} from "./js/components/glass-terminal.js";
import { initLensEffect } from "./js/components/lens.js";
import { initFrameworkViz } from "./js/components/framework-viz.js";
import { initHeroShader } from "./js/effects/hero-shader.js";
import { initScrollReveal } from "./js/utils/reveal.js";
import { initScrollIndicator, initSmoothScroll, initHashTracking } from "./js/utils/scroll.js";
import { initAnchorScroll, initHashTracking } from "./js/utils/scroll.js";
import { initThemeToggle } from "./js/utils/theme.js";
// ============================================
// STATE
@@ -315,10 +315,9 @@ function initLightbox() {
// ============================================
function init() {
initSmoothScroll();
initScrollIndicator();
initThemeToggle();
initAnchorScroll();
initHashTracking();
initHeroShader();
initLensEffect();
initScrollReveal();
initGlassTerminal();
+242 -260
View File
@@ -61,11 +61,78 @@
--color-accent-hover: oklch(52% 0.25 350);
--color-accent-dim: oklch(60% 0.25 350 / 0.15);
--color-accent-soft: oklch(60% 0.25 350 / 0.25);
/* Framework category colors - Light mode */
--cat-diagnostic-bg: #fdf4ff;
--cat-diagnostic-border: #d946ef;
--cat-diagnostic-text: #a21caf;
--cat-quality-bg: #f0fdf4;
--cat-quality-border: #22c55e;
--cat-quality-text: #15803d;
--cat-intensity-bg: #fffbeb;
--cat-intensity-border: #f59e0b;
--cat-intensity-text: #b45309;
--cat-adaptation-bg: #eff6ff;
--cat-adaptation-border: #3b82f6;
--cat-adaptation-text: #1d4ed8;
--cat-enhancement-bg: #fdf2f8;
--cat-enhancement-border: #ec4899;
--cat-enhancement-text: #be185d;
--cat-system-bg: #f5f5f4;
--cat-system-border: #78716c;
--cat-system-text: #44403c;
}
/* Dark Mode */
/* Dark Mode - Class-based for toggle support */
html.dark {
--color-ink: oklch(98% 0 0);
--color-text: oklch(98% 0 0);
--color-paper: oklch(10% 0 0);
--color-cream: oklch(12% 0.005 350);
--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);
--color-accent-dim: oklch(68% 0.23 350 / 0.15);
--color-accent-soft: oklch(68% 0.23 350 / 0.25);
/* Framework category colors - Dark mode (muted backgrounds, brighter accents) */
--cat-diagnostic-bg: #2d1f3d;
--cat-diagnostic-border: #c084fc;
--cat-diagnostic-text: #e879f9;
--cat-quality-bg: #14332a;
--cat-quality-border: #4ade80;
--cat-quality-text: #86efac;
--cat-intensity-bg: #362a1a;
--cat-intensity-border: #fbbf24;
--cat-intensity-text: #fcd34d;
--cat-adaptation-bg: #1e293b;
--cat-adaptation-border: #60a5fa;
--cat-adaptation-text: #93c5fd;
--cat-enhancement-bg: #3b1f32;
--cat-enhancement-border: #f472b6;
--cat-enhancement-text: #f9a8d4;
--cat-system-bg: #1c1917;
--cat-system-border: #a8a29e;
--cat-system-text: #d6d3d1;
}
/* System preference fallback (when no explicit preference is set) */
@media (prefers-color-scheme: dark) {
:root {
html:not(.light):not(.dark) {
--color-ink: oklch(98% 0 0);
--color-text: oklch(98% 0 0);
--color-paper: oklch(10% 0 0);
@@ -74,14 +141,84 @@
--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);
--color-accent-dim: oklch(68% 0.23 350 / 0.15);
--color-accent-soft: oklch(68% 0.23 350 / 0.25);
/* Framework category colors - Dark mode */
--cat-diagnostic-bg: #2d1f3d;
--cat-diagnostic-border: #c084fc;
--cat-diagnostic-text: #e879f9;
--cat-quality-bg: #14332a;
--cat-quality-border: #4ade80;
--cat-quality-text: #86efac;
--cat-intensity-bg: #362a1a;
--cat-intensity-border: #fbbf24;
--cat-intensity-text: #fcd34d;
--cat-adaptation-bg: #1e293b;
--cat-adaptation-border: #60a5fa;
--cat-adaptation-text: #93c5fd;
--cat-enhancement-bg: #3b1f32;
--cat-enhancement-border: #f472b6;
--cat-enhancement-text: #f9a8d4;
--cat-system-bg: #1c1917;
--cat-system-border: #a8a29e;
--cat-system-text: #d6d3d1;
}
}
/* Theme Toggle */
.theme-toggle {
position: fixed;
bottom: var(--spacing-md);
right: var(--spacing-md);
z-index: 10001;
display: flex;
align-items: center;
background: var(--color-cream);
border: 1px solid var(--color-mist);
border-radius: 100px;
padding: 4px;
gap: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.theme-toggle-btn {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: none;
background: transparent;
border-radius: 50%;
color: var(--color-ash);
cursor: pointer;
transition: all 0.2s ease;
}
.theme-toggle-btn:hover {
color: var(--color-charcoal);
background: var(--color-mist);
}
.theme-toggle-btn.active {
color: var(--color-paper);
background: var(--color-ink);
}
.theme-toggle-btn svg {
width: 16px;
height: 16px;
}
/* ============================================
SKIP LINK (Accessibility)
============================================ */
@@ -119,23 +256,6 @@ html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
scroll-behavior: smooth;
}
html.lenis, html.lenis body {
height: auto;
}
.lenis.lenis-smooth {
scroll-behavior: auto !important;
}
.lenis.lenis-smooth [data-lenis-prevent] {
overscroll-behavior: contain;
}
.lenis.lenis-stopped {
overflow: hidden;
}
body {
@@ -278,54 +398,52 @@ code {
}
/* ============================================
HERO SECTION
HERO SECTION - Combined Layout
============================================ */
/* Hero shader viewport - first thing, full screen */
.hero-shader {
width: 100vw;
height: 100vh;
height: 100dvh;
position: relative;
}
.hero-shader canvas {
width: 100% !important;
height: 100% !important;
}
/* Overlay content centered on shader */
.hero-overlay-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
.hero-combined {
min-height: 100vh;
min-height: 100dvh;
display: flex;
flex-direction: column;
justify-content: center;
padding: var(--spacing-xl) var(--spacing-lg);
background: var(--color-paper);
}
.hero-combined-container {
max-width: var(--width-max);
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-xl);
align-items: center;
width: 100%;
}
@media (max-width: 1024px) {
.hero-combined-container {
grid-template-columns: 1fr;
gap: var(--spacing-lg);
text-align: center;
}
}
.hero-combined-left {
display: flex;
flex-direction: column;
gap: var(--spacing-md);
text-align: center;
pointer-events: none;
}
.hero-badge {
display: inline-block;
padding: 0.35em 1em;
font-family: var(--font-body);
font-size: 0.75rem;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--color-ink);
background: rgba(255, 255, 255, 0.85);
border: 1px solid var(--color-ink);
backdrop-filter: blur(4px);
@media (max-width: 1024px) {
.hero-combined-left {
align-items: center;
}
}
.hero-title-overlay {
.hero-title-combined {
font-family: var(--font-display);
font-size: clamp(3.5rem, 12vw, 8rem);
font-size: clamp(3.5rem, 10vw, 7rem);
font-weight: 300;
font-style: italic;
line-height: 1;
@@ -334,22 +452,40 @@ code {
color: var(--color-ink);
}
.hero-tagline-overlay {
.hero-tagline-combined {
font-family: var(--font-display);
font-size: clamp(1rem, 2.5vw, 1.5rem);
font-size: clamp(1.125rem, 2.5vw, 1.75rem);
font-weight: 400;
font-style: italic;
line-height: 1.4;
line-height: 1.3;
margin: 0;
color: var(--color-ink);
opacity: 0.8;
max-width: 400px;
color: var(--color-charcoal);
}
.hero-cta-overlay {
pointer-events: auto;
.hero-problem-text {
font-size: clamp(1rem, 1.5vw, 1.125rem);
line-height: 1.6;
color: var(--color-ash);
max-width: 45ch;
margin: 0;
}
.hero-cta-group {
display: flex;
align-items: center;
gap: var(--spacing-lg);
margin-top: var(--spacing-sm);
}
@media (max-width: 600px) {
.hero-cta-group {
flex-direction: column;
gap: var(--spacing-md);
}
}
.hero-cta-combined {
display: inline-block;
margin-top: var(--spacing-md);
padding: var(--spacing-sm) var(--spacing-xl);
font-family: var(--font-body);
font-size: 0.9rem;
@@ -360,225 +496,71 @@ code {
color: var(--color-paper);
background: var(--color-ink);
border: none;
transition: transform 0.2s ease, opacity 0.2s ease;
transition: transform 0.2s ease, background 0.2s ease;
}
.hero-cta-overlay:hover {
.hero-cta-combined:hover {
transform: translateY(-2px);
opacity: 0.9;
background: var(--color-accent);
color: var(--color-paper);
}
/* Content section below shader */
.hero-container {
position: relative;
text-align: center;
max-width: 1000px;
width: 100%;
margin: 0 auto;
padding: var(--spacing-2xl) var(--spacing-lg);
background: var(--color-paper);
}
.hero-section-title {
font-family: var(--font-display);
font-size: clamp(1.5rem, 4vw, 2rem);
font-weight: 400;
font-style: italic;
color: var(--color-ink);
margin: 0 0 var(--spacing-lg) 0;
}
.hero-content {
.hero-logos-inline {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--spacing-xl);
height: 100%;
}
.hero-header {
text-align: center;
}
.hero-footer {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
}
.hero-eyebrow {
font-family: var(--font-mono);
font-size: 0.8125rem;
font-weight: 500;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--color-accent);
/* Animation handled by JS reveal.js */
}
.hero-title {
font-size: clamp(3.5rem, 12vw, 8rem);
font-weight: 300;
font-style: italic;
line-height: 1;
letter-spacing: -0.02em;
margin: 0;
color: var(--color-ink);
}
.hero-title-line {
display: block;
}
.hero-title-accent {
font-style: italic;
color: var(--color-accent);
}
.hero-subtitle {
font-size: clamp(1rem, 2.5vw, 1.375rem);
color: var(--color-charcoal);
max-width: 45ch;
line-height: 1.5;
}
.hero-providers {
font-size: 0.8125rem;
.hero-logos-inline .hero-logos-label {
font-size: 0.6875rem;
color: var(--color-ash);
letter-spacing: 0.03em;
}
.hero-tagline {
font-family: var(--font-display);
font-size: clamp(1rem, 1.8vw, 1.25rem);
font-style: italic;
color: var(--color-ash);
letter-spacing: 0.02em;
margin-top: var(--spacing-sm);
}
/* Hero Equation */
.hero-equation {
display: flex;
align-items: stretch;
gap: var(--spacing-md);
width: 100%;
}
.equation-block {
flex: 1;
padding: var(--spacing-sm) var(--spacing-md);
border: 2px solid var(--color-ink);
border-radius: 0;
background: var(--color-cream);
text-align: left;
}
.equation-label {
display: inline-block;
font-family: var(--font-body);
font-size: 0.625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.12em;
color: var(--color-cream);
background: var(--color-ink);
padding: 2px 8px;
margin-bottom: var(--spacing-xs);
}
.equation-title {
display: block;
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
font-size: clamp(1.125rem, 2vw, 1.5rem);
font-weight: 600;
color: var(--color-ink);
margin-bottom: var(--spacing-xs);
}
.equation-list {
list-style: none;
padding: 0;
margin: 0;
font-size: 0.8125rem;
color: var(--color-charcoal);
line-height: 1.6;
white-space: nowrap;
}
.equation-operator {
.hero-logos-inline .hero-logos-row {
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-display);
font-size: 2.5rem;
font-weight: 300;
color: var(--color-accent);
flex-shrink: 0;
width: 48px;
gap: 8px;
}
@media (max-width: 768px) {
.hero-equation {
flex-direction: column;
gap: var(--spacing-sm);
}
.equation-operator {
font-size: 1.75rem;
width: auto;
padding: var(--spacing-xs) 0;
}
}
.hero-logos {
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.hero-logos-label {
font-size: 0.75rem;
color: var(--color-ash);
letter-spacing: 0.03em;
}
.hero-logos-row {
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.hero-logos-row img {
.hero-logos-inline .hero-logos-row img {
border-radius: 4px;
opacity: 0.7;
transition: opacity 0.2s ease;
}
.hero-scroll-indicator {
position: absolute;
bottom: var(--spacing-lg);
left: 50%;
transform: translateX(-50%);
.hero-logos-inline .hero-logos-row img:hover {
opacity: 1;
}
.hero-combined-right {
display: flex;
justify-content: center;
}
.hero-combined-right .split-comparison {
max-width: 520px;
width: 100%;
}
.hero-combined-right .split-container {
max-width: 100%;
}
/* Bias tags at bottom of hero */
.hero-bias-tags {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-xs);
color: var(--color-ash);
font-size: 0.6875rem;
font-weight: 500;
letter-spacing: 0.1em;
text-transform: uppercase;
opacity: 0;
/* Restore simple CSS animation */
animation: fadeIn 1s var(--ease-out) 1.5s forwards, float 2s ease-in-out infinite 2s;
}
/* Removed .revealed dependency for scroll indicator */
.hero-scroll-indicator svg {
/* No separate bounce animation needed, handled by float */
margin-top: var(--spacing-lg);
padding-top: var(--spacing-md);
border-top: 1px solid var(--color-mist);
max-width: var(--width-max);
margin-left: auto;
margin-right: auto;
width: 100%;
padding-bottom: var(--spacing-md);
}
/* ============================================
+7 -12
View File
@@ -139,7 +139,7 @@
font-family: var(--font-mono);
font-size: 0.75rem;
padding: 5px 12px;
background: var(--color-mist);
background: var(--color-cream);
border: 1px solid var(--color-mist);
border-bottom: none;
border-radius: 6px 6px 0 0;
@@ -201,14 +201,12 @@
/* Source Window Content */
.source-window {
background: rgba(255, 255, 255, 0.95);
background: var(--color-paper);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--color-mist);
border-radius: 8px;
box-shadow:
0 20px 60px -10px rgba(0,0,0,0.15),
0 0 0 1px rgba(255,255,255,0.5) inset;
box-shadow: 0 20px 60px -10px rgba(0,0,0,0.15);
height: 100%;
display: flex;
flex-direction: column;
@@ -216,7 +214,7 @@
}
.source-header {
background: rgba(0,0,0,0.02);
background: var(--color-cream);
padding: 12px 16px;
display: flex;
align-items: center;
@@ -259,15 +257,12 @@
}
.glass-terminal {
background: rgba(255, 255, 255, 0.9);
/* Glass effect handled by backdrop-filter if supported */
background: var(--color-paper);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid var(--color-mist);
border-radius: 8px;
box-shadow:
0 20px 60px -10px rgba(0,0,0,0.15),
0 0 0 1px rgba(255,255,255,0.5) inset;
box-shadow: 0 20px 60px -10px rgba(0,0,0,0.15);
height: 100%;
display: flex;
flex-direction: column;
@@ -275,7 +270,7 @@
}
.terminal-header {
background: rgba(0,0,0,0.02);
background: var(--color-cream);
padding: 12px 16px;
display: flex;
align-items: center;
+50 -87
View File
@@ -38,81 +38,54 @@
<!-- Grain Overlay -->
<div class="grain-overlay" aria-hidden="true"></div>
<!-- 1. HERO -->
<section id="hero">
<!-- Shader viewport with overlayed content -->
<div class="hero-shader" id="hero-shader">
<div class="hero-overlay-content">
<h1 class="hero-title-overlay">Impeccable</h1>
<p class="hero-tagline-overlay">Design fluency for Claude Code, Codex, and more.</p>
<a href="#downloads" class="hero-cta-overlay">Get Started</a>
</div>
</div>
<!-- Theme Toggle -->
<div class="theme-toggle" role="group" aria-label="Theme switcher">
<button class="theme-toggle-btn" data-theme="light" aria-label="Light theme" title="Light theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="5"/>
<path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/>
</svg>
</button>
<button class="theme-toggle-btn" data-theme="system" aria-label="System theme" title="System theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="3" width="20" height="14" rx="2"/>
<path d="M8 21h8M12 17v4"/>
</svg>
</button>
<button class="theme-toggle-btn" data-theme="dark" aria-label="Dark theme" title="Dark theme">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
</svg>
</button>
</div>
<!-- Content below the shader -->
<div class="hero-container">
<div class="hero-content">
<h2 class="hero-section-title" data-reveal>What's Included</h2>
<!-- 1. HERO - Combined with Problem Section -->
<section id="hero" class="hero-combined">
<div class="hero-combined-container">
<!-- Left: Title & Info -->
<div class="hero-combined-left">
<h1 class="hero-title-combined">Impeccable</h1>
<p class="hero-tagline-combined">Design fluency for AI coding tools</p>
<!-- Visual Equation -->
<div class="hero-equation" data-reveal>
<div class="equation-block">
<span class="equation-label">Enhanced Skill</span>
<span class="equation-title">frontend-design</span>
<ul class="equation-list">
<li>Anthropic's original skill</li>
<li>+ curated anti-patterns</li>
<li>+ 7 deep reference guides</li>
</ul>
</div>
<p class="hero-problem-text">Every LLM learned from the same generic templates. Without explicit guidance, they converge on predictable defaults.</p>
<span class="equation-operator">+</span>
<div class="equation-block">
<span class="equation-label">Steering Commands</span>
<span class="equation-title">17 commands</span>
<ul class="equation-list">
<li>/polish, /audit, /simplify</li>
<li>/bolder, /quieter, /animate</li>
<li>and 11 more...</li>
</ul>
</div>
</div>
<!-- Bottom: Logos -->
<div class="hero-footer" data-reveal>
<div class="hero-logos">
<div class="hero-cta-group">
<a href="#downloads" class="hero-cta-combined">Get Started</a>
<div class="hero-logos-inline">
<span class="hero-logos-label">Works with</span>
<div class="hero-logos-row">
<img src="https://img.logo.dev/cursor.com?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Cursor" width="30" height="30" loading="lazy">
<img src="https://img.logo.dev/claude.ai?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Claude Code" width="30" height="30" loading="lazy">
<img src="https://img.logo.dev/gemini.google.com?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Gemini CLI" width="24" height="24" loading="lazy">
<img src="https://img.logo.dev/openai.com?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Codex CLI" width="24" height="24" loading="lazy">
<img src="https://img.logo.dev/cursor.com?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Cursor" width="24" height="24" loading="lazy">
<img src="https://img.logo.dev/claude.ai?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Claude Code" width="24" height="24" loading="lazy">
<img src="https://img.logo.dev/gemini.google.com?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Gemini CLI" width="20" height="20" loading="lazy">
<img src="https://img.logo.dev/openai.com?token=pk_dtRHfeTyRzG5zZInUc65Xw&size=64&format=png" alt="Codex CLI" width="20" height="20" loading="lazy">
</div>
</div>
</div>
</div>
</div>
<div class="hero-scroll-indicator" aria-hidden="true">
<span>Scroll</span>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M12 5v14M19 12l-7 7-7-7"/>
</svg>
</div>
</header>
<main class="site-content" id="main-content">
<!-- 2. THE PROBLEM - AI Design Bias -->
<section class="problem-section" id="problem">
<div class="section-header" data-reveal>
<span class="section-number">01</span>
<h2 class="section-title">AI Has Design Bias</h2>
</div>
<div class="problem-content">
<p class="section-lead" data-reveal>Every LLM learned from the same generic templates. Without explicit guidance, they converge on the same predictable defaults.</p>
<!-- Before/After Demo - The Hero -->
<div class="split-comparison" id="lens-comparison" data-reveal>
<!-- Right: Before/After Demo -->
<div class="hero-combined-right">
<div class="split-comparison" id="lens-comparison">
<div class="split-container">
<!-- Before: AI Slop -->
<div class="split-before">
@@ -160,26 +133,16 @@
</div>
</div>
</div>
<!-- Compact Bias Tags -->
<div class="bias-tags" data-reveal>
<span class="bias-tags-label">Common AI defaults:</span>
<div class="bias-tags-list">
<span class="bias-tag">Inter/Roboto fonts</span>
<span class="bias-tag">Purple gradients</span>
<span class="bias-tag">Cards on cards</span>
<span class="bias-tag">Centered everything</span>
<span class="bias-tag">Gray text on color</span>
<span class="bias-tag">Decorative shadows</span>
</div>
</div>
</div>
</section>
</div>
</section>
<!-- 3. THE ANTIDOTE - Patterns & Anti-Patterns -->
<main class="site-content" id="main-content">
<!-- 2. THE ANTIDOTE - Patterns & Anti-Patterns -->
<section class="antidote-section" id="antidote">
<div class="section-header" data-reveal>
<span class="section-number">02</span>
<span class="section-number">01</span>
<h2 class="section-title">The Antidote</h2>
</div>
<div class="antidote-content">
@@ -203,10 +166,10 @@
</div>
</section>
<!-- 4. THE SOLUTION - Two-part system -->
<!-- 3. THE SOLUTION - Two-part system -->
<section class="solution-section" id="solution">
<div class="section-header" data-reveal>
<span class="section-number">03</span>
<span class="section-number">02</span>
<h2 class="section-title">The Framework</h2>
</div>
<div class="solution-content">
@@ -226,7 +189,7 @@
<!-- 4. COMMANDS - Glass Terminal -->
<section class="commands-section" id="commands-section">
<div class="section-header" data-reveal>
<span class="section-number">04</span>
<span class="section-number">03</span>
<h2 class="section-title">Commands in Action</h2>
<p class="section-subtitle">See how commands transform your designs</p>
</div>
@@ -239,7 +202,7 @@
<!-- 5. CASE STUDIES -->
<section class="casestudies-section" id="casestudies">
<div class="section-header" data-reveal>
<span class="section-number">05</span>
<span class="section-number">04</span>
<h2 class="section-title">See It In Action</h2>
<p class="section-subtitle">Sample projects transformed with Impeccable commands</p>
</div>
@@ -335,7 +298,7 @@
<!-- 6. PLATFORMS -->
<section class="platforms-section" id="downloads">
<div class="section-header" data-reveal>
<span class="section-number">06</span>
<span class="section-number">05</span>
<h2 class="section-title">Download for Your AI Harness</h2>
<p class="section-subtitle">Same design intelligence, adapted for your workflow. Download and start using in seconds.</p>
</div>
@@ -438,7 +401,7 @@
<!-- 7. FAQ -->
<section class="faq-section" id="faq">
<div class="section-header" data-reveal>
<span class="section-number">07</span>
<span class="section-number">06</span>
<h2 class="section-title">Frequently Asked Questions</h2>
</div>
+7 -6
View File
@@ -5,13 +5,14 @@
import { commandCategories, commandRelationships } from '../data.js';
// Colors now reference CSS custom properties for dark mode support
const categoryColors = {
diagnostic: { bg: '#fdf4ff', border: '#d946ef', text: '#a21caf' },
quality: { bg: '#f0fdf4', border: '#22c55e', text: '#15803d' },
intensity: { bg: '#fffbeb', border: '#f59e0b', text: '#b45309' },
adaptation: { bg: '#eff6ff', border: '#3b82f6', text: '#1d4ed8' },
enhancement: { bg: '#fdf2f8', border: '#ec4899', text: '#be185d' },
system: { bg: '#f9fafb', border: '#6b7280', text: '#374151' }
diagnostic: { bg: 'var(--cat-diagnostic-bg)', border: 'var(--cat-diagnostic-border)', text: 'var(--cat-diagnostic-text)' },
quality: { bg: 'var(--cat-quality-bg)', border: 'var(--cat-quality-border)', text: 'var(--cat-quality-text)' },
intensity: { bg: 'var(--cat-intensity-bg)', border: 'var(--cat-intensity-border)', text: 'var(--cat-intensity-text)' },
adaptation: { bg: 'var(--cat-adaptation-bg)', border: 'var(--cat-adaptation-border)', text: 'var(--cat-adaptation-text)' },
enhancement: { bg: 'var(--cat-enhancement-bg)', border: 'var(--cat-enhancement-border)', text: 'var(--cat-enhancement-text)' },
system: { bg: 'var(--cat-system-bg)', border: 'var(--cat-system-border)', text: 'var(--cat-system-text)' }
};
const categoryLabels = {
+10 -60
View File
@@ -1,69 +1,17 @@
import Lenis from "lenis";
// Check if user prefers reduced motion
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
export function initSmoothScroll() {
// Skip smooth scroll entirely if user prefers reduced motion
if (prefersReducedMotion) {
// Still handle anchor links but with instant scroll
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
anchor.addEventListener("click", (e) => {
e.preventDefault();
const target = document.querySelector(anchor.getAttribute("href"));
if (target) {
target.scrollIntoView({ behavior: 'auto', block: 'start' });
}
});
});
return null;
}
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - 2 ** (-10 * t)),
orientation: "vertical",
gestureOrientation: "vertical",
smoothWheel: true,
wheelMultiplier: 1,
touchMultiplier: 2,
});
function raf(time) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
// Handle anchor links
// Instant anchor scroll - no smooth scrolling for better UX on long pages
export function initAnchorScroll() {
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
anchor.addEventListener("click", (e) => {
e.preventDefault();
const target = document.querySelector(anchor.getAttribute("href"));
if (target) {
lenis.scrollTo(target, { offset: -40 });
// Instant jump with small offset for visual breathing room
const offset = 40;
const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({ top: targetPosition, behavior: 'auto' });
}
});
});
return lenis;
}
export function initScrollIndicator() {
const indicator = document.querySelector(".hero-scroll-indicator");
if (!indicator) return;
function update() {
if (window.scrollY > 20) {
indicator.classList.add("hidden");
} else {
indicator.classList.remove("hidden");
}
}
window.addEventListener("scroll", update, { passive: true });
update();
}
export function initHashTracking() {
@@ -109,12 +57,14 @@ export function initHashTracking() {
}
}, { passive: true });
// Handle initial hash on page load
// Handle initial hash on page load - instant jump
if (window.location.hash) {
const target = document.querySelector(window.location.hash);
if (target) {
setTimeout(() => {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
const offset = 40;
const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset;
window.scrollTo({ top: targetPosition, behavior: 'auto' });
}, 100);
}
}
+56
View File
@@ -0,0 +1,56 @@
// Theme toggle - supports light, dark, and system preference
const STORAGE_KEY = 'impeccable-theme';
function getStoredTheme() {
return localStorage.getItem(STORAGE_KEY);
}
function setStoredTheme(theme) {
localStorage.setItem(STORAGE_KEY, theme);
}
function applyTheme(theme) {
const html = document.documentElement;
// Remove both classes first
html.classList.remove('light', 'dark');
if (theme === 'light') {
html.classList.add('light');
} else if (theme === 'dark') {
html.classList.add('dark');
}
// 'system' = no class, falls back to media query
// Update active state on buttons
document.querySelectorAll('.theme-toggle-btn').forEach(btn => {
btn.classList.toggle('active', btn.dataset.theme === theme);
});
}
export function initThemeToggle() {
const toggle = document.querySelector('.theme-toggle');
if (!toggle) return;
// Get stored theme or default to system
const storedTheme = getStoredTheme() || 'system';
applyTheme(storedTheme);
// Handle button clicks
toggle.addEventListener('click', (e) => {
const btn = e.target.closest('.theme-toggle-btn');
if (!btn) return;
const theme = btn.dataset.theme;
setStoredTheme(theme);
applyTheme(theme);
});
// Listen for system preference changes (only matters when in 'system' mode)
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (getStoredTheme() === 'system' || !getStoredTheme()) {
applyTheme('system');
}
});
}