From 059ab1b1e65844d151f81c8c1e79aabb4f9975c0 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 15 Mar 2026 19:13:53 -0700 Subject: [PATCH 01/14] feat: add /typeset and /arrange skills for typography and layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new skills that expose frontend-design's typography and spatial design references as actionable, diagnostic workflows: - /typeset: assess and improve font choices, hierarchy, sizing, weight consistency, and readability (closes #26) - /arrange: assess and improve layout, spacing, visual rhythm, and grid structure Both follow the established skill pattern (assess → plan → execute → verify) with MANDATORY PREPARATION and context gathering. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/arrange/SKILL.md | 123 ++++++++++++++++++++++++++++++++ .claude/skills/typeset/SKILL.md | 117 ++++++++++++++++++++++++++++++ source/skills/arrange/SKILL.md | 123 ++++++++++++++++++++++++++++++++ source/skills/typeset/SKILL.md | 117 ++++++++++++++++++++++++++++++ 4 files changed, 480 insertions(+) create mode 100644 .claude/skills/arrange/SKILL.md create mode 100644 .claude/skills/typeset/SKILL.md create mode 100644 source/skills/arrange/SKILL.md create mode 100644 source/skills/typeset/SKILL.md diff --git a/.claude/skills/arrange/SKILL.md b/.claude/skills/arrange/SKILL.md new file mode 100644 index 000000000..74c21596c --- /dev/null +++ b/.claude/skills/arrange/SKILL.md @@ -0,0 +1,123 @@ +--- +name: arrange +description: Improve layout, spacing, and visual rhythm. Fixes monotonous grids, inconsistent spacing, and weak visual hierarchy to create intentional compositions. +user-invokable: true +args: + - name: target + description: The feature or component to improve layout for (optional) + required: false +--- + +Assess and improve layout and spacing that feels monotonous, crowded, or structurally weak — turning generic arrangements into intentional, rhythmic compositions. + +## MANDATORY PREPARATION + +Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. + +--- + +## Assess Current Layout + +Analyze what's weak about the current spatial design: + +1. **Spacing**: + - Is spacing consistent or arbitrary? (Random padding/margin values) + - Is all spacing the same? (Equal padding everywhere = no rhythm) + - Are related elements grouped tightly, with generous space between groups? + +2. **Visual hierarchy**: + - Apply the squint test: blur your eyes — can you still identify the most important element, second most important, and clear groupings? + - Is hierarchy achieved through size alone, or through multiple dimensions? (Size + weight + color + space) + - Does whitespace guide the eye to what matters? + +3. **Grid & structure**: + - Is there a clear underlying structure, or does the layout feel random? + - Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly) + - Is everything centered? (Left-aligned with asymmetric layouts feels more designed) + +4. **Rhythm & variety**: + - Does the layout have visual rhythm? (Alternating tight/generous spacing) + - Is every section structured the same way? (Monotonous repetition) + - Are there intentional moments of surprise or emphasis? + +5. **Density**: + - Is the layout too cramped? (Not enough breathing room) + - Is the layout too sparse? (Excessive whitespace without purpose) + - Does density match the content type? (Data-dense UIs need tighter spacing; marketing pages need more air) + +**CRITICAL**: Layout problems are often the root cause of interfaces feeling "off" even when colors and fonts are fine. Space is a design material — use it with intention. + +## Plan Layout Improvements + +Consult the [spatial design reference](reference/spatial-design.md) from the frontend-design skill for detailed guidance on grids, rhythm, and container queries. + +Create a systematic plan: + +- **Spacing system**: Establish a scale (4pt base: 4, 8, 12, 16, 24, 32, 48, 64, 96px) +- **Hierarchy strategy**: How will space, size, and position communicate importance? +- **Grid approach**: What structure fits the content? (Fixed grid, auto-fit, named areas) +- **Rhythm**: Where should spacing be tight vs generous? + +## Improve Layout Systematically + +### Establish a Spacing System + +- Adopt a 4pt base grid for all spacing values +- Name tokens semantically: `--space-xs`, `--space-sm`, `--space-md`, `--space-lg`, `--space-xl` +- Use `gap` for sibling spacing instead of margins — eliminates margin collapse hacks +- Apply `clamp()` for fluid spacing that breathes on larger screens + +### Create Visual Rhythm + +- **Tight grouping** for related elements (8-12px between siblings) +- **Generous separation** between distinct sections (48-96px) +- **Varied spacing** within sections — not every row needs the same gap +- **Asymmetric compositions** — break the predictable centered-content pattern when it makes sense + +### Fix Grid & Structure + +- Use `repeat(auto-fit, minmax(280px, 1fr))` for responsive grids without breakpoints +- Use named grid areas (`grid-template-areas`) for complex layouts — redefine at breakpoints +- Don't default to card grids for everything — spacing and alignment create visual grouping naturally +- Use cards only when content is truly distinct and actionable — never nest cards inside cards + +### Strengthen Visual Hierarchy + +- Combine dimensions: size + weight + color + space for strong hierarchy +- Surround important elements with generous whitespace — space draws attention +- Use position strategically: top-left reads as primary, bottom-right as secondary +- Create clear content groupings through proximity and separation + +### Manage Depth & Elevation + +- Create a semantic z-index scale (dropdown → sticky → modal-backdrop → modal → toast → tooltip) +- Build a consistent shadow scale (sm → md → lg → xl) — shadows should be subtle +- Use elevation to reinforce hierarchy, not as decoration + +### Optical Adjustments + +- Text at `margin-left: 0` looks indented — use small negative margin to optically align +- Geometrically centered icons often look off-center — adjust visually +- Touch targets need 44px minimum regardless of visual size — use padding or pseudo-elements + +**NEVER**: +- Use arbitrary spacing values outside your scale +- Make all spacing equal — variety creates hierarchy +- Wrap everything in cards — not everything needs a container +- Nest cards inside cards — use spacing and dividers for hierarchy within +- Use identical card grids everywhere (icon + heading + text, repeated) +- Center everything — left-aligned with asymmetry feels more designed +- Use the hero metric layout template (big number, small label, stats, gradient) +- Rely on size alone for hierarchy — combine size, weight, color, and space +- Use arbitrary z-index values (999, 9999) — build a semantic scale + +## Verify Layout Improvements + +- **Squint test**: Can you identify primary, secondary, and groupings with blurred vision? +- **Rhythm**: Does the page have a satisfying beat of tight and generous spacing? +- **Hierarchy**: Is the most important content obvious within 2 seconds? +- **Breathing room**: Does the layout feel comfortable, not cramped or wasteful? +- **Consistency**: Is the spacing system applied uniformly? +- **Responsiveness**: Does the layout adapt gracefully across screen sizes? + +Remember: Space is the most underused design tool. A layout with the right rhythm and hierarchy can make even simple content feel polished and intentional. \ No newline at end of file diff --git a/.claude/skills/typeset/SKILL.md b/.claude/skills/typeset/SKILL.md new file mode 100644 index 000000000..d768c3f7b --- /dev/null +++ b/.claude/skills/typeset/SKILL.md @@ -0,0 +1,117 @@ +--- +name: typeset +description: Improve typography by fixing font choices, hierarchy, sizing, weight consistency, and readability. Makes text feel intentional and polished. +user-invokable: true +args: + - name: target + description: The feature or component to improve typography for (optional) + required: false +--- + +Assess and improve typography that feels generic, inconsistent, or poorly structured — turning default-looking text into intentional, well-crafted type. + +## MANDATORY PREPARATION + +Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. + +--- + +## Assess Current Typography + +Analyze what's weak or generic about the current type: + +1. **Font choices**: + - Are we using invisible defaults? (Inter, Roboto, Arial, Open Sans, system defaults) + - Does the font match the brand personality? (A playful brand shouldn't use a corporate typeface) + - Are there too many font families? (More than 2-3 is almost always a mess) + +2. **Hierarchy**: + - Can you tell headings from body from captions at a glance? + - Are font sizes too close together? (14px, 15px, 16px = muddy hierarchy) + - Are weight contrasts strong enough? (Medium vs Regular is barely visible) + +3. **Sizing & scale**: + - Is there a consistent type scale, or are sizes arbitrary? + - Does body text meet minimum readability? (16px+) + - Is fluid sizing used, or do sizes jump at breakpoints? + +4. **Readability**: + - Are line lengths comfortable? (45-75 characters ideal) + - Is line-height appropriate for the font and context? + - Is there enough contrast between text and background? + +5. **Consistency**: + - Are the same elements styled the same way throughout? + - Are font weights used consistently? (Not bold in one section, semibold in another for the same role) + - Is letter-spacing intentional or default everywhere? + +**CRITICAL**: The goal isn't to make text "fancier" — it's to make it clearer, more readable, and more intentional. Good typography is invisible; bad typography is distracting. + +## Plan Typography Improvements + +Consult the [typography reference](reference/typography.md) from the frontend-design skill for detailed guidance on scales, pairing, and loading strategies. + +Create a systematic plan: + +- **Font selection**: Do fonts need replacing? What fits the brand/context? +- **Type scale**: Establish a modular scale (e.g., 1.25 ratio) with clear hierarchy +- **Weight strategy**: Which weights serve which roles? (Regular for body, Semibold for labels, Bold for headings — or whatever fits) +- **Spacing**: Line-heights, letter-spacing, and margins between typographic elements + +## Improve Typography Systematically + +### Font Selection + +If fonts need replacing: +- Choose fonts that reflect the brand personality +- Pair with genuine contrast (serif + sans, geometric + humanist) — or use a single family in multiple weights +- Ensure web font loading doesn't cause layout shift (`font-display: swap`, metric-matched fallbacks) + +### Establish Hierarchy + +Build a clear type scale: +- **5 sizes cover most needs**: caption, secondary, body, subheading, heading +- **Use a consistent ratio** between levels (1.25, 1.333, or 1.5) +- **Combine dimensions**: Size + weight + color + space for strong hierarchy — don't rely on size alone +- **Use fluid sizing**: `clamp(min, preferred, max)` for smooth scaling + +### Fix Readability + +- Set `max-width` on text containers using `ch` units (`max-width: 65ch`) +- Adjust line-height per context: tighter for headings (1.1-1.2), looser for body (1.5-1.7) +- Increase line-height slightly for light-on-dark text +- Ensure body text is at least 16px / 1rem + +### Refine Details + +- Use `tabular-nums` for data tables and numbers that should align +- Apply proper `letter-spacing`: slightly open for small caps and uppercase, default or tight for large display text +- Use semantic token names (`--text-body`, `--text-heading`), not value names (`--font-16`) +- Set `font-kerning: normal` and consider OpenType features where appropriate + +### Weight Consistency + +- Define clear roles for each weight and stick to them +- Don't use more than 3-4 weights (Regular, Medium, Semibold, Bold is plenty) +- Load only the weights you actually use (each weight adds to page load) + +**NEVER**: +- Use more than 2-3 font families +- Pick sizes arbitrarily — commit to a scale +- Set body text below 16px +- Use decorative/display fonts for body text +- Disable browser zoom (`user-scalable=no`) +- Use `px` for font sizes — use `rem` to respect user settings +- Default to Inter/Roboto/Open Sans when personality matters +- Pair fonts that are similar but not identical (two geometric sans-serifs) + +## Verify Typography Improvements + +- **Hierarchy**: Can you identify heading vs body vs caption instantly? +- **Readability**: Is body text comfortable to read in long passages? +- **Consistency**: Are same-role elements styled identically throughout? +- **Personality**: Does the typography reflect the brand? +- **Performance**: Are web fonts loading efficiently without layout shift? +- **Accessibility**: Does text meet WCAG contrast ratios? Is it zoomable to 200%? + +Remember: Typography is the foundation of interface design — it carries the majority of information. Getting it right is the highest-leverage improvement you can make. \ No newline at end of file diff --git a/source/skills/arrange/SKILL.md b/source/skills/arrange/SKILL.md new file mode 100644 index 000000000..44f95516d --- /dev/null +++ b/source/skills/arrange/SKILL.md @@ -0,0 +1,123 @@ +--- +name: arrange +description: Improve layout, spacing, and visual rhythm. Fixes monotonous grids, inconsistent spacing, and weak visual hierarchy to create intentional compositions. +args: + - name: target + description: The feature or component to improve layout for (optional) + required: false +user-invokable: true +--- + +Assess and improve layout and spacing that feels monotonous, crowded, or structurally weak — turning generic arrangements into intentional, rhythmic compositions. + +## MANDATORY PREPARATION + +Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. + +--- + +## Assess Current Layout + +Analyze what's weak about the current spatial design: + +1. **Spacing**: + - Is spacing consistent or arbitrary? (Random padding/margin values) + - Is all spacing the same? (Equal padding everywhere = no rhythm) + - Are related elements grouped tightly, with generous space between groups? + +2. **Visual hierarchy**: + - Apply the squint test: blur your eyes — can you still identify the most important element, second most important, and clear groupings? + - Is hierarchy achieved through size alone, or through multiple dimensions? (Size + weight + color + space) + - Does whitespace guide the eye to what matters? + +3. **Grid & structure**: + - Is there a clear underlying structure, or does the layout feel random? + - Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly) + - Is everything centered? (Left-aligned with asymmetric layouts feels more designed) + +4. **Rhythm & variety**: + - Does the layout have visual rhythm? (Alternating tight/generous spacing) + - Is every section structured the same way? (Monotonous repetition) + - Are there intentional moments of surprise or emphasis? + +5. **Density**: + - Is the layout too cramped? (Not enough breathing room) + - Is the layout too sparse? (Excessive whitespace without purpose) + - Does density match the content type? (Data-dense UIs need tighter spacing; marketing pages need more air) + +**CRITICAL**: Layout problems are often the root cause of interfaces feeling "off" even when colors and fonts are fine. Space is a design material — use it with intention. + +## Plan Layout Improvements + +Consult the [spatial design reference](reference/spatial-design.md) from the frontend-design skill for detailed guidance on grids, rhythm, and container queries. + +Create a systematic plan: + +- **Spacing system**: Establish a scale (4pt base: 4, 8, 12, 16, 24, 32, 48, 64, 96px) +- **Hierarchy strategy**: How will space, size, and position communicate importance? +- **Grid approach**: What structure fits the content? (Fixed grid, auto-fit, named areas) +- **Rhythm**: Where should spacing be tight vs generous? + +## Improve Layout Systematically + +### Establish a Spacing System + +- Adopt a 4pt base grid for all spacing values +- Name tokens semantically: `--space-xs`, `--space-sm`, `--space-md`, `--space-lg`, `--space-xl` +- Use `gap` for sibling spacing instead of margins — eliminates margin collapse hacks +- Apply `clamp()` for fluid spacing that breathes on larger screens + +### Create Visual Rhythm + +- **Tight grouping** for related elements (8-12px between siblings) +- **Generous separation** between distinct sections (48-96px) +- **Varied spacing** within sections — not every row needs the same gap +- **Asymmetric compositions** — break the predictable centered-content pattern when it makes sense + +### Fix Grid & Structure + +- Use `repeat(auto-fit, minmax(280px, 1fr))` for responsive grids without breakpoints +- Use named grid areas (`grid-template-areas`) for complex layouts — redefine at breakpoints +- Don't default to card grids for everything — spacing and alignment create visual grouping naturally +- Use cards only when content is truly distinct and actionable — never nest cards inside cards + +### Strengthen Visual Hierarchy + +- Combine dimensions: size + weight + color + space for strong hierarchy +- Surround important elements with generous whitespace — space draws attention +- Use position strategically: top-left reads as primary, bottom-right as secondary +- Create clear content groupings through proximity and separation + +### Manage Depth & Elevation + +- Create a semantic z-index scale (dropdown → sticky → modal-backdrop → modal → toast → tooltip) +- Build a consistent shadow scale (sm → md → lg → xl) — shadows should be subtle +- Use elevation to reinforce hierarchy, not as decoration + +### Optical Adjustments + +- Text at `margin-left: 0` looks indented — use small negative margin to optically align +- Geometrically centered icons often look off-center — adjust visually +- Touch targets need 44px minimum regardless of visual size — use padding or pseudo-elements + +**NEVER**: +- Use arbitrary spacing values outside your scale +- Make all spacing equal — variety creates hierarchy +- Wrap everything in cards — not everything needs a container +- Nest cards inside cards — use spacing and dividers for hierarchy within +- Use identical card grids everywhere (icon + heading + text, repeated) +- Center everything — left-aligned with asymmetry feels more designed +- Use the hero metric layout template (big number, small label, stats, gradient) +- Rely on size alone for hierarchy — combine size, weight, color, and space +- Use arbitrary z-index values (999, 9999) — build a semantic scale + +## Verify Layout Improvements + +- **Squint test**: Can you identify primary, secondary, and groupings with blurred vision? +- **Rhythm**: Does the page have a satisfying beat of tight and generous spacing? +- **Hierarchy**: Is the most important content obvious within 2 seconds? +- **Breathing room**: Does the layout feel comfortable, not cramped or wasteful? +- **Consistency**: Is the spacing system applied uniformly? +- **Responsiveness**: Does the layout adapt gracefully across screen sizes? + +Remember: Space is the most underused design tool. A layout with the right rhythm and hierarchy can make even simple content feel polished and intentional. diff --git a/source/skills/typeset/SKILL.md b/source/skills/typeset/SKILL.md new file mode 100644 index 000000000..2bf23e183 --- /dev/null +++ b/source/skills/typeset/SKILL.md @@ -0,0 +1,117 @@ +--- +name: typeset +description: Improve typography by fixing font choices, hierarchy, sizing, weight consistency, and readability. Makes text feel intentional and polished. +args: + - name: target + description: The feature or component to improve typography for (optional) + required: false +user-invokable: true +--- + +Assess and improve typography that feels generic, inconsistent, or poorly structured — turning default-looking text into intentional, well-crafted type. + +## MANDATORY PREPARATION + +Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. + +--- + +## Assess Current Typography + +Analyze what's weak or generic about the current type: + +1. **Font choices**: + - Are we using invisible defaults? (Inter, Roboto, Arial, Open Sans, system defaults) + - Does the font match the brand personality? (A playful brand shouldn't use a corporate typeface) + - Are there too many font families? (More than 2-3 is almost always a mess) + +2. **Hierarchy**: + - Can you tell headings from body from captions at a glance? + - Are font sizes too close together? (14px, 15px, 16px = muddy hierarchy) + - Are weight contrasts strong enough? (Medium vs Regular is barely visible) + +3. **Sizing & scale**: + - Is there a consistent type scale, or are sizes arbitrary? + - Does body text meet minimum readability? (16px+) + - Is fluid sizing used, or do sizes jump at breakpoints? + +4. **Readability**: + - Are line lengths comfortable? (45-75 characters ideal) + - Is line-height appropriate for the font and context? + - Is there enough contrast between text and background? + +5. **Consistency**: + - Are the same elements styled the same way throughout? + - Are font weights used consistently? (Not bold in one section, semibold in another for the same role) + - Is letter-spacing intentional or default everywhere? + +**CRITICAL**: The goal isn't to make text "fancier" — it's to make it clearer, more readable, and more intentional. Good typography is invisible; bad typography is distracting. + +## Plan Typography Improvements + +Consult the [typography reference](reference/typography.md) from the frontend-design skill for detailed guidance on scales, pairing, and loading strategies. + +Create a systematic plan: + +- **Font selection**: Do fonts need replacing? What fits the brand/context? +- **Type scale**: Establish a modular scale (e.g., 1.25 ratio) with clear hierarchy +- **Weight strategy**: Which weights serve which roles? (Regular for body, Semibold for labels, Bold for headings — or whatever fits) +- **Spacing**: Line-heights, letter-spacing, and margins between typographic elements + +## Improve Typography Systematically + +### Font Selection + +If fonts need replacing: +- Choose fonts that reflect the brand personality +- Pair with genuine contrast (serif + sans, geometric + humanist) — or use a single family in multiple weights +- Ensure web font loading doesn't cause layout shift (`font-display: swap`, metric-matched fallbacks) + +### Establish Hierarchy + +Build a clear type scale: +- **5 sizes cover most needs**: caption, secondary, body, subheading, heading +- **Use a consistent ratio** between levels (1.25, 1.333, or 1.5) +- **Combine dimensions**: Size + weight + color + space for strong hierarchy — don't rely on size alone +- **Use fluid sizing**: `clamp(min, preferred, max)` for smooth scaling + +### Fix Readability + +- Set `max-width` on text containers using `ch` units (`max-width: 65ch`) +- Adjust line-height per context: tighter for headings (1.1-1.2), looser for body (1.5-1.7) +- Increase line-height slightly for light-on-dark text +- Ensure body text is at least 16px / 1rem + +### Refine Details + +- Use `tabular-nums` for data tables and numbers that should align +- Apply proper `letter-spacing`: slightly open for small caps and uppercase, default or tight for large display text +- Use semantic token names (`--text-body`, `--text-heading`), not value names (`--font-16`) +- Set `font-kerning: normal` and consider OpenType features where appropriate + +### Weight Consistency + +- Define clear roles for each weight and stick to them +- Don't use more than 3-4 weights (Regular, Medium, Semibold, Bold is plenty) +- Load only the weights you actually use (each weight adds to page load) + +**NEVER**: +- Use more than 2-3 font families +- Pick sizes arbitrarily — commit to a scale +- Set body text below 16px +- Use decorative/display fonts for body text +- Disable browser zoom (`user-scalable=no`) +- Use `px` for font sizes — use `rem` to respect user settings +- Default to Inter/Roboto/Open Sans when personality matters +- Pair fonts that are similar but not identical (two geometric sans-serifs) + +## Verify Typography Improvements + +- **Hierarchy**: Can you identify heading vs body vs caption instantly? +- **Readability**: Is body text comfortable to read in long passages? +- **Consistency**: Are same-role elements styled identically throughout? +- **Personality**: Does the typography reflect the brand? +- **Performance**: Are web fonts loading efficiently without layout shift? +- **Accessibility**: Does text meet WCAG contrast ratios? Is it zoomable to 200%? + +Remember: Typography is the foundation of interface design — it carries the majority of information. Getting it right is the highest-leverage improvement you can make. From 45bcf7b4854d6d7f4a8a5d51a39649ccdd39d5fb Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 15 Mar 2026 19:26:35 -0700 Subject: [PATCH 02/14] Add typeset and arrange to website, docs, and all metadata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add to data.js (process steps, categories, relationships) - Add to framework-viz.js (periodic table symbols and numbers) - Create before/after demos for both commands - Update command count 17→19 across all locations: index.html, cheatsheet.html, README, NOTICE, AGENTS, plugin.json, marketplace.json - Add critique→typeset/arrange in relationship flow - Add "Adding New Skills" checklist to CLAUDE.md so future skill additions don't miss any locations Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude-plugin/marketplace.json | 4 +-- .claude-plugin/plugin.json | 2 +- AGENTS.md | 2 +- CLAUDE.md | 15 ++++++++ NOTICE.md | 2 +- README.md | 8 +++-- public/cheatsheet.html | 14 +++++--- public/index.html | 10 +++--- public/js/components/framework-viz.js | 8 +++-- public/js/data.js | 14 +++++--- public/js/demos/commands/arrange.js | 50 +++++++++++++++++++++++++++ public/js/demos/commands/index.js | 4 +++ public/js/demos/commands/typeset.js | 23 ++++++++++++ 13 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 public/js/demos/commands/arrange.js create mode 100644 public/js/demos/commands/typeset.js diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 39e681432..a40e07883 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -2,7 +2,7 @@ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "impeccable", "metadata": { - "description": "Design fluency for AI harnesses. 1 skill, 17 commands, and curated anti-patterns for impeccable frontend design." + "description": "Design fluency for AI harnesses. 1 skill, 19 commands, and curated anti-patterns for impeccable frontend design." }, "owner": { "name": "Paul Bakaus", @@ -11,7 +11,7 @@ "plugins": [ { "name": "impeccable", - "description": "Design vocabulary and skills for frontend development. Includes 17 commands (/polish, /distill, /audit, /bolder, /quieter, etc.) and an enhanced frontend-design skill with curated anti-patterns.", + "description": "Design vocabulary and skills for frontend development. Includes 19 commands (/polish, /distill, /audit, /typeset, /arrange, etc.) and an enhanced frontend-design skill with curated anti-patterns.", "version": "1.3.0", "author": { "name": "Paul Bakaus", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ff9296bf0..ae647c5c8 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "impeccable", - "description": "Design vocabulary and skills for frontend development. Includes 18 skills (17 user-invokable: /polish, /distill, /audit, /bolder, /quieter, etc.) and an enhanced frontend-design skill with curated anti-patterns.", + "description": "Design vocabulary and skills for frontend development. Includes 20 skills (19 user-invokable: /polish, /distill, /audit, /typeset, /arrange, etc.) and an enhanced frontend-design skill with curated anti-patterns.", "version": "1.3.0", "author": { "name": "Paul Bakaus", diff --git a/AGENTS.md b/AGENTS.md index 03e9b0a6b..3119602a7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # Impeccable -The vocabulary you didn't know you needed. 1 skill, 17 commands, and curated anti-patterns for impeccable style. Works with Cursor, Claude Code, Gemini CLI, and Codex CLI. +The vocabulary you didn't know you needed. 1 skill, 19 commands, and curated anti-patterns for impeccable style. Works with Cursor, Claude Code, Gemini CLI, and Codex CLI. ## Repository Purpose diff --git a/CLAUDE.md b/CLAUDE.md index 55507dd63..33de089a2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,3 +50,18 @@ When bumping the version, update **all** of these locations to keep them in sync - `.claude-plugin/plugin.json` → `version` - `.claude-plugin/marketplace.json` → `plugins[0].version` - `public/index.html` → hero version link text + new changelog entry + +## Adding New Skills + +When adding a new user-invokable skill, update the command count in **all** of these locations: + +- `public/index.html` → meta descriptions, hero box, section lead +- `public/cheatsheet.html` → meta description, subtitle, `commandCategories`, `commandRelationships` +- `public/js/data.js` → `commandProcessSteps`, `commandCategories`, `commandRelationships` +- `public/js/components/framework-viz.js` → `commandSymbols`, `commandNumbers` +- `public/js/demos/commands/` → new demo file + import in `index.js` +- `README.md` → intro, command count, commands table +- `NOTICE.md` → steering commands count +- `AGENTS.md` → intro command count +- `.claude-plugin/plugin.json` → description +- `.claude-plugin/marketplace.json` → metadata description + plugin description diff --git a/NOTICE.md b/NOTICE.md index 1920a3307..c74d45c23 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -13,5 +13,5 @@ The `frontend-design` skill in this project builds on Anthropic's original front This project extends the original with: - 7 domain-specific reference files (typography, color-and-contrast, spatial-design, motion-design, interaction-design, responsive-design, ux-writing) -- 17 steering commands +- 19 steering commands - Expanded patterns and anti-patterns diff --git a/README.md b/README.md index 973da610e..fa200af4d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Impeccable -The vocabulary you didn't know you needed. 1 skill, 17 commands, and curated anti-patterns for impeccable frontend design. +The vocabulary you didn't know you needed. 1 skill, 19 commands, and curated anti-patterns for impeccable frontend design. > **Quick start:** Visit [impeccable.style](https://impeccable.style) to download ready-to-use bundles. @@ -12,7 +12,7 @@ Every LLM learned from the same generic templates. Without guidance, you get the Impeccable fights that bias with: - **An expanded skill** with 7 domain-specific reference files ([view source](source/skills/frontend-design/)) -- **17 steering commands** to audit, review, polish, distill, animate, and more +- **19 steering commands** to audit, review, polish, distill, animate, and more - **Curated anti-patterns** that explicitly tell the AI what NOT to do ## What's Included @@ -31,7 +31,7 @@ A comprehensive design skill with 7 domain-specific references ([view skill](sou | [responsive-design](source/skills/frontend-design/reference/responsive-design.md) | Mobile-first, fluid design, container queries | | [ux-writing](source/skills/frontend-design/reference/ux-writing.md) | Button labels, error messages, empty states | -### 17 Commands +### 19 Commands | Command | What it does | |---------|--------------| @@ -52,6 +52,8 @@ A comprehensive design skill with 7 domain-specific references ([view skill](sou | `/extract` | Pull into reusable components | | `/adapt` | Adapt for different devices | | `/onboard` | Design onboarding flows | +| `/typeset` | Fix font choices, hierarchy, sizing | +| `/arrange` | Fix layout, spacing, visual rhythm | ### Anti-Patterns diff --git a/public/cheatsheet.html b/public/cheatsheet.html index 179a09307..094b782f4 100644 --- a/public/cheatsheet.html +++ b/public/cheatsheet.html @@ -4,7 +4,7 @@ Impeccable Command Cheatsheet - + @@ -160,7 +160,7 @@

Impeccable Commands

-

Quick reference for all 17 design commands

+

Quick reference for all 19 design commands

← Back to impeccable.style
@@ -201,13 +201,15 @@ 'delight': 'enhancement', 'extract': 'system', 'adapt': 'adaptation', - 'onboard': 'enhancement' + 'onboard': 'enhancement', + 'typeset': 'enhancement', + 'arrange': 'enhancement' }; const commandRelationships = { 'teach-impeccable': { flow: 'One-time project context gathering' }, 'audit': { leadsTo: ['normalize', 'harden', 'optimize', 'adapt', 'clarify'], flow: 'Technical quality audit' }, - 'critique': { leadsTo: ['polish', 'distill', 'bolder', 'quieter'], flow: 'UX and design review' }, + 'critique': { leadsTo: ['polish', 'distill', 'bolder', 'quieter', 'typeset', 'arrange'], flow: 'UX and design review' }, 'normalize': { combinesWith: ['clarify', 'adapt'], flow: 'Align with design system' }, 'polish': { flow: 'Final pass before shipping' }, 'optimize': { flow: 'Performance improvements' }, @@ -221,7 +223,9 @@ 'delight': { combinesWith: ['bolder', 'animate'], flow: 'Add personality' }, 'extract': { flow: 'Create design system elements' }, 'adapt': { combinesWith: ['normalize', 'clarify'], flow: 'Different devices/contexts' }, - 'onboard': { combinesWith: ['clarify', 'delight'], flow: 'Onboarding & empty states' } + 'onboard': { combinesWith: ['clarify', 'delight'], flow: 'Onboarding & empty states' }, + 'typeset': { combinesWith: ['bolder', 'normalize'], flow: 'Fix typography' }, + 'arrange': { combinesWith: ['distill', 'adapt'], flow: 'Fix layout & spacing' } }; async function loadCommands() { diff --git a/public/index.html b/public/index.html index 220094f3c..bcbf78be0 100644 --- a/public/index.html +++ b/public/index.html @@ -4,7 +4,7 @@ Impeccable: The missing upgrade to Anthropic's frontend-design skill - + @@ -12,7 +12,7 @@ - + @@ -20,7 +20,7 @@ - + @@ -57,7 +57,7 @@
Enhanced frontend-design skill + anti-patterns · - 17 design skills: /polish, /audit, /distill, /bolder... + 19 design skills: /polish, /audit, /typeset, /arrange...
@@ -162,7 +162,7 @@

The Framework

-

One comprehensive skill with deep expertise, plus 17 commands that form the language of design.

+

One comprehensive skill with deep expertise, plus 19 commands that form the language of design.

diff --git a/public/js/components/framework-viz.js b/public/js/components/framework-viz.js index bac0e0bda..a20455872 100644 --- a/public/js/components/framework-viz.js +++ b/public/js/components/framework-viz.js @@ -42,7 +42,9 @@ const commandSymbols = { delight: 'De', bolder: 'Bo', quieter: 'Qu', - onboard: 'On' + onboard: 'On', + typeset: 'Ty', + arrange: 'Ar' }; // Atomic numbers (just for visual interest) @@ -63,7 +65,9 @@ const commandNumbers = { delight: 13, bolder: 14, quieter: 15, - onboard: 16 + onboard: 16, + typeset: 17, + arrange: 18 }; export class PeriodicTable { diff --git a/public/js/data.js b/public/js/data.js index 15f3f6cab..2e0c49cde 100644 --- a/public/js/data.js +++ b/public/js/data.js @@ -53,7 +53,9 @@ export const commandProcessSteps = { 'delight': ['Identify', 'Design', 'Implement'], 'extract': ['Identify', 'Abstract', 'Document'], 'adapt': ['Analyze', 'Adjust', 'Optimize'], - 'onboard': ['Map', 'Design', 'Guide'] + 'onboard': ['Map', 'Design', 'Guide'], + 'typeset': ['Assess', 'Select', 'Scale', 'Refine'], + 'arrange': ['Assess', 'Grid', 'Rhythm', 'Balance'] }; export const commandCategories = { @@ -73,7 +75,9 @@ export const commandCategories = { 'delight': 'enhancement', 'extract': 'system', 'adapt': 'adaptation', - 'onboard': 'enhancement' + 'onboard': 'enhancement', + 'typeset': 'enhancement', + 'arrange': 'enhancement' }; // Skill relationships - now consolidated into frontend-design skill @@ -88,7 +92,7 @@ export const skillRelationships = { export const commandRelationships = { 'teach-impeccable': { flow: 'Setup: One-time project context gathering' }, 'audit': { leadsTo: ['normalize', 'harden', 'optimize', 'adapt', 'clarify'], flow: 'Diagnostic: Technical quality audit' }, - 'critique': { leadsTo: ['polish', 'distill', 'bolder', 'quieter'], flow: 'Diagnostic: UX and design review' }, + 'critique': { leadsTo: ['polish', 'distill', 'bolder', 'quieter', 'typeset', 'arrange'], flow: 'Diagnostic: UX and design review' }, 'normalize': { combinesWith: ['clarify', 'adapt'], flow: 'Quality: Align with design system' }, 'polish': { flow: 'Quality: Final pass before shipping' }, 'optimize': { flow: 'Quality: Performance improvements' }, @@ -102,6 +106,8 @@ export const commandRelationships = { 'delight': { combinesWith: ['bolder', 'animate'], flow: 'Enhancement: Add personality' }, 'extract': { flow: 'System: Create design system elements' }, 'adapt': { combinesWith: ['normalize', 'clarify'], flow: 'Adaptation: Different devices/contexts' }, - 'onboard': { combinesWith: ['clarify', 'delight'], flow: 'Enhancement: Onboarding & empty states' } + 'onboard': { combinesWith: ['clarify', 'delight'], flow: 'Enhancement: Onboarding & empty states' }, + 'typeset': { combinesWith: ['bolder', 'normalize'], flow: 'Enhancement: Fix typography' }, + 'arrange': { combinesWith: ['distill', 'adapt'], flow: 'Enhancement: Fix layout & spacing' } }; diff --git a/public/js/demos/commands/arrange.js b/public/js/demos/commands/arrange.js new file mode 100644 index 000000000..e9299c6a8 --- /dev/null +++ b/public/js/demos/commands/arrange.js @@ -0,0 +1,50 @@ +// Arrange command demo - shows monotonous equal spacing becoming rhythmic and intentional +export default { + id: 'arrange', + caption: 'Equal spacing everywhere → Intentional rhythm and hierarchy', + + before: ` +
+
+
Team Members
+
+
+
+
+
Alice Chen
+
Designer
+
+
+
+
Bob Park
+
Engineer
+
+
+
+ `, + + after: ` +
+
+
Team
+
Members
+
+
+
+
AC
+
+
Alice Chen
+
Designer
+
+
+
+
BP
+
+
Bob Park
+
Engineer
+
+
+
+
+ ` +}; diff --git a/public/js/demos/commands/index.js b/public/js/demos/commands/index.js index 95c30f12a..f57744725 100644 --- a/public/js/demos/commands/index.js +++ b/public/js/demos/commands/index.js @@ -16,6 +16,8 @@ import delight from "./delight.js"; import extract from "./extract.js"; import adapt from "./adapt.js"; import onboard from "./onboard.js"; +import typeset from "./typeset.js"; +import arrange from "./arrange.js"; export const commandDemos = { normalize, @@ -34,6 +36,8 @@ export const commandDemos = { extract, adapt, onboard, + typeset, + arrange, }; export function getCommandDemo(commandId) { diff --git a/public/js/demos/commands/typeset.js b/public/js/demos/commands/typeset.js new file mode 100644 index 000000000..2f226e054 --- /dev/null +++ b/public/js/demos/commands/typeset.js @@ -0,0 +1,23 @@ +// Typeset command demo - shows generic typography becoming intentional and hierarchical +export default { + id: 'typeset', + caption: 'Generic system fonts → Intentional type hierarchy', + + before: ` +
+
Project Update
+
Q1 Design Sprint
+

The team completed the redesign of the dashboard. All components have been reviewed and approved by stakeholders.

+
Updated 2 hours ago
+
+ `, + + after: ` +
+
Project Update
+
Q1 Design Sprint
+

The team completed the redesign of the dashboard. All components reviewed and approved.

+
Updated 2 hours ago
+
+ ` +}; From 9dd959abe27969f3b9f9fc8c1035098469aa68d9 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 15 Mar 2026 19:40:22 -0700 Subject: [PATCH 03/14] Refine /arrange skill based on review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace prescriptive 4pt px grid with flexible guidance (framework scales, rem tokens, custom systems — consistency matters, not values) - Add Flex vs Grid guidance — don't default to Grid when Flex is simpler - Soften hierarchy advice: fewest dimensions needed, not "combine all" - Remove margin-left optical trick (confusing, too niche) - Remove touch target advice (belongs in /adapt and /audit) - Add qualifier to icon centering (only adjust if confident) - Fix position hierarchy to be about reading flow awareness, not rules - Change hero metric from NEVER to nuanced DON'T (legitimate for real data, problematic as default template) Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/arrange/SKILL.md | 44 ++++++++++++++++++--------------- source/skills/arrange/SKILL.md | 44 ++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/.claude/skills/arrange/SKILL.md b/.claude/skills/arrange/SKILL.md index 74c21596c..3c91bf7f4 100644 --- a/.claude/skills/arrange/SKILL.md +++ b/.claude/skills/arrange/SKILL.md @@ -26,14 +26,14 @@ Analyze what's weak about the current spatial design: - Are related elements grouped tightly, with generous space between groups? 2. **Visual hierarchy**: - - Apply the squint test: blur your eyes — can you still identify the most important element, second most important, and clear groupings? - - Is hierarchy achieved through size alone, or through multiple dimensions? (Size + weight + color + space) + - Apply the squint test: blur your (metaphorical) eyes — can you still identify the most important element, second most important, and clear groupings? + - Is hierarchy achieved effectively? (Space and weight alone can be enough — but is the current approach working?) - Does whitespace guide the eye to what matters? 3. **Grid & structure**: - Is there a clear underlying structure, or does the layout feel random? - Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly) - - Is everything centered? (Left-aligned with asymmetric layouts feels more designed) + - Is everything centered? (Left-aligned with asymmetric layouts feels more designed, but not a hard and fast rule) 4. **Rhythm & variety**: - Does the layout have visual rhythm? (Alternating tight/generous spacing) @@ -53,17 +53,17 @@ Consult the [spatial design reference](reference/spatial-design.md) from the fro Create a systematic plan: -- **Spacing system**: Establish a scale (4pt base: 4, 8, 12, 16, 24, 32, 48, 64, 96px) -- **Hierarchy strategy**: How will space, size, and position communicate importance? -- **Grid approach**: What structure fits the content? (Fixed grid, auto-fit, named areas) +- **Spacing system**: Use a consistent scale — whether that's a framework's built-in scale (e.g., Tailwind), rem-based tokens, or a custom system. The specific values matter less than consistency. +- **Hierarchy strategy**: How will space communicate importance? +- **Layout approach**: What structure fits the content? Flex for 1D, Grid for 2D, named areas for complex page layouts. - **Rhythm**: Where should spacing be tight vs generous? ## Improve Layout Systematically ### Establish a Spacing System -- Adopt a 4pt base grid for all spacing values -- Name tokens semantically: `--space-xs`, `--space-sm`, `--space-md`, `--space-lg`, `--space-xl` +- Use a consistent spacing scale — framework scales (Tailwind, etc.), rem-based tokens, or a custom scale all work. What matters is that values come from a defined set, not arbitrary numbers. +- Name tokens semantically if using custom properties: `--space-xs` through `--space-xl`, not `--spacing-8` - Use `gap` for sibling spacing instead of margins — eliminates margin collapse hacks - Apply `clamp()` for fluid spacing that breathes on larger screens @@ -74,19 +74,25 @@ Create a systematic plan: - **Varied spacing** within sections — not every row needs the same gap - **Asymmetric compositions** — break the predictable centered-content pattern when it makes sense -### Fix Grid & Structure +### Choose the Right Layout Tool + +- **Use Flexbox for 1D layouts**: Rows of items, nav bars, button groups, card contents, most component internals. Flex is simpler and more appropriate for the majority of layout tasks. +- **Use Grid for 2D layouts**: Page-level structure, dashboards, data-dense interfaces, anything where rows AND columns need coordinated control. +- **Don't default to Grid** when Flexbox with `flex-wrap` would be simpler and more flexible. +- Use `repeat(auto-fit, minmax(280px, 1fr))` for responsive grids without breakpoints. +- Use named grid areas (`grid-template-areas`) for complex page layouts — redefine at breakpoints. + +### Break Card Grid Monotony -- Use `repeat(auto-fit, minmax(280px, 1fr))` for responsive grids without breakpoints -- Use named grid areas (`grid-template-areas`) for complex layouts — redefine at breakpoints - Don't default to card grids for everything — spacing and alignment create visual grouping naturally - Use cards only when content is truly distinct and actionable — never nest cards inside cards +- Vary card sizes, span columns, or mix cards with non-card content to break repetition ### Strengthen Visual Hierarchy -- Combine dimensions: size + weight + color + space for strong hierarchy -- Surround important elements with generous whitespace — space draws attention -- Use position strategically: top-left reads as primary, bottom-right as secondary -- Create clear content groupings through proximity and separation +- Use the fewest dimensions needed for clear hierarchy. Space alone can be enough — generous whitespace around an element draws the eye. Some of the most sophisticated designs achieve rhythm with just space and weight. Add color or size contrast only when simpler means aren't sufficient. +- Be aware of reading flow — in LTR languages, the eye naturally scans top-left to bottom-right, but primary action placement depends on context (e.g., bottom-right in dialogs, top in navigation). +- Create clear content groupings through proximity and separation. ### Manage Depth & Elevation @@ -96,9 +102,7 @@ Create a systematic plan: ### Optical Adjustments -- Text at `margin-left: 0` looks indented — use small negative margin to optically align -- Geometrically centered icons often look off-center — adjust visually -- Touch targets need 44px minimum regardless of visual size — use padding or pseudo-elements +- If an icon looks visually off-center despite being geometrically centered, nudge it — but only if you're confident it actually looks wrong. Don't adjust speculatively. **NEVER**: - Use arbitrary spacing values outside your scale @@ -107,8 +111,8 @@ Create a systematic plan: - Nest cards inside cards — use spacing and dividers for hierarchy within - Use identical card grids everywhere (icon + heading + text, repeated) - Center everything — left-aligned with asymmetry feels more designed -- Use the hero metric layout template (big number, small label, stats, gradient) -- Rely on size alone for hierarchy — combine size, weight, color, and space +- Default to the hero metric layout (big number, small label, stats, gradient) as a template. If showing real user data, a prominent metric can work — but it should display actual data, not decorative numbers. +- Default to CSS Grid when Flexbox would be simpler — use the simplest tool for the job - Use arbitrary z-index values (999, 9999) — build a semantic scale ## Verify Layout Improvements diff --git a/source/skills/arrange/SKILL.md b/source/skills/arrange/SKILL.md index 44f95516d..98eaea2b9 100644 --- a/source/skills/arrange/SKILL.md +++ b/source/skills/arrange/SKILL.md @@ -26,14 +26,14 @@ Analyze what's weak about the current spatial design: - Are related elements grouped tightly, with generous space between groups? 2. **Visual hierarchy**: - - Apply the squint test: blur your eyes — can you still identify the most important element, second most important, and clear groupings? - - Is hierarchy achieved through size alone, or through multiple dimensions? (Size + weight + color + space) + - Apply the squint test: blur your (metaphorical) eyes — can you still identify the most important element, second most important, and clear groupings? + - Is hierarchy achieved effectively? (Space and weight alone can be enough — but is the current approach working?) - Does whitespace guide the eye to what matters? 3. **Grid & structure**: - Is there a clear underlying structure, or does the layout feel random? - Are identical card grids used everywhere? (Icon + heading + text, repeated endlessly) - - Is everything centered? (Left-aligned with asymmetric layouts feels more designed) + - Is everything centered? (Left-aligned with asymmetric layouts feels more designed, but not a hard and fast rule) 4. **Rhythm & variety**: - Does the layout have visual rhythm? (Alternating tight/generous spacing) @@ -53,17 +53,17 @@ Consult the [spatial design reference](reference/spatial-design.md) from the fro Create a systematic plan: -- **Spacing system**: Establish a scale (4pt base: 4, 8, 12, 16, 24, 32, 48, 64, 96px) -- **Hierarchy strategy**: How will space, size, and position communicate importance? -- **Grid approach**: What structure fits the content? (Fixed grid, auto-fit, named areas) +- **Spacing system**: Use a consistent scale — whether that's a framework's built-in scale (e.g., Tailwind), rem-based tokens, or a custom system. The specific values matter less than consistency. +- **Hierarchy strategy**: How will space communicate importance? +- **Layout approach**: What structure fits the content? Flex for 1D, Grid for 2D, named areas for complex page layouts. - **Rhythm**: Where should spacing be tight vs generous? ## Improve Layout Systematically ### Establish a Spacing System -- Adopt a 4pt base grid for all spacing values -- Name tokens semantically: `--space-xs`, `--space-sm`, `--space-md`, `--space-lg`, `--space-xl` +- Use a consistent spacing scale — framework scales (Tailwind, etc.), rem-based tokens, or a custom scale all work. What matters is that values come from a defined set, not arbitrary numbers. +- Name tokens semantically if using custom properties: `--space-xs` through `--space-xl`, not `--spacing-8` - Use `gap` for sibling spacing instead of margins — eliminates margin collapse hacks - Apply `clamp()` for fluid spacing that breathes on larger screens @@ -74,19 +74,25 @@ Create a systematic plan: - **Varied spacing** within sections — not every row needs the same gap - **Asymmetric compositions** — break the predictable centered-content pattern when it makes sense -### Fix Grid & Structure +### Choose the Right Layout Tool + +- **Use Flexbox for 1D layouts**: Rows of items, nav bars, button groups, card contents, most component internals. Flex is simpler and more appropriate for the majority of layout tasks. +- **Use Grid for 2D layouts**: Page-level structure, dashboards, data-dense interfaces, anything where rows AND columns need coordinated control. +- **Don't default to Grid** when Flexbox with `flex-wrap` would be simpler and more flexible. +- Use `repeat(auto-fit, minmax(280px, 1fr))` for responsive grids without breakpoints. +- Use named grid areas (`grid-template-areas`) for complex page layouts — redefine at breakpoints. + +### Break Card Grid Monotony -- Use `repeat(auto-fit, minmax(280px, 1fr))` for responsive grids without breakpoints -- Use named grid areas (`grid-template-areas`) for complex layouts — redefine at breakpoints - Don't default to card grids for everything — spacing and alignment create visual grouping naturally - Use cards only when content is truly distinct and actionable — never nest cards inside cards +- Vary card sizes, span columns, or mix cards with non-card content to break repetition ### Strengthen Visual Hierarchy -- Combine dimensions: size + weight + color + space for strong hierarchy -- Surround important elements with generous whitespace — space draws attention -- Use position strategically: top-left reads as primary, bottom-right as secondary -- Create clear content groupings through proximity and separation +- Use the fewest dimensions needed for clear hierarchy. Space alone can be enough — generous whitespace around an element draws the eye. Some of the most sophisticated designs achieve rhythm with just space and weight. Add color or size contrast only when simpler means aren't sufficient. +- Be aware of reading flow — in LTR languages, the eye naturally scans top-left to bottom-right, but primary action placement depends on context (e.g., bottom-right in dialogs, top in navigation). +- Create clear content groupings through proximity and separation. ### Manage Depth & Elevation @@ -96,9 +102,7 @@ Create a systematic plan: ### Optical Adjustments -- Text at `margin-left: 0` looks indented — use small negative margin to optically align -- Geometrically centered icons often look off-center — adjust visually -- Touch targets need 44px minimum regardless of visual size — use padding or pseudo-elements +- If an icon looks visually off-center despite being geometrically centered, nudge it — but only if you're confident it actually looks wrong. Don't adjust speculatively. **NEVER**: - Use arbitrary spacing values outside your scale @@ -107,8 +111,8 @@ Create a systematic plan: - Nest cards inside cards — use spacing and dividers for hierarchy within - Use identical card grids everywhere (icon + heading + text, repeated) - Center everything — left-aligned with asymmetry feels more designed -- Use the hero metric layout template (big number, small label, stats, gradient) -- Rely on size alone for hierarchy — combine size, weight, color, and space +- Default to the hero metric layout (big number, small label, stats, gradient) as a template. If showing real user data, a prominent metric can work — but it should display actual data, not decorative numbers. +- Default to CSS Grid when Flexbox would be simpler — use the simplest tool for the job - Use arbitrary z-index values (999, 9999) — build a semantic scale ## Verify Layout Improvements From 731c0ceaf7f2eaed54a12320b5a40547ffbf5b40 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 15 Mar 2026 19:58:02 -0700 Subject: [PATCH 04/14] feat: add /overdrive skill for technically extraordinary effects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New skill that pushes interfaces past conventional limits with bleeding-edge browser APIs: WebGPU shaders, scroll-driven animations, View Transitions, generative art, spring physics, and more. Key design decisions: - Strong "when to use / when not to" guardrails - Progressive enhancement is non-negotiable - "Pick ONE hero moment" philosophy — restraint in choosing where - The extraordinary/gimmicky line defined explicitly - prefers-reduced-motion respect required Also updates all counts to 20 commands across website, docs, and plugin metadata. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude-plugin/marketplace.json | 4 +- .claude-plugin/plugin.json | 2 +- .claude/skills/overdrive/SKILL.md | 161 ++++++++++++++++++++++++++ AGENTS.md | 2 +- NOTICE.md | 2 +- README.md | 7 +- public/cheatsheet.html | 10 +- public/index.html | 10 +- public/js/components/framework-viz.js | 6 +- public/js/data.js | 9 +- public/js/demos/commands/index.js | 2 + public/js/demos/commands/overdrive.js | 31 +++++ source/skills/overdrive/SKILL.md | 161 ++++++++++++++++++++++++++ 13 files changed, 385 insertions(+), 22 deletions(-) create mode 100644 .claude/skills/overdrive/SKILL.md create mode 100644 public/js/demos/commands/overdrive.js create mode 100644 source/skills/overdrive/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index a40e07883..3787cbe17 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -2,7 +2,7 @@ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", "name": "impeccable", "metadata": { - "description": "Design fluency for AI harnesses. 1 skill, 19 commands, and curated anti-patterns for impeccable frontend design." + "description": "Design fluency for AI harnesses. 1 skill, 20 commands, and curated anti-patterns for impeccable frontend design." }, "owner": { "name": "Paul Bakaus", @@ -11,7 +11,7 @@ "plugins": [ { "name": "impeccable", - "description": "Design vocabulary and skills for frontend development. Includes 19 commands (/polish, /distill, /audit, /typeset, /arrange, etc.) and an enhanced frontend-design skill with curated anti-patterns.", + "description": "Design vocabulary and skills for frontend development. Includes 20 commands (/polish, /distill, /audit, /typeset, /overdrive, etc.) and an enhanced frontend-design skill with curated anti-patterns.", "version": "1.3.0", "author": { "name": "Paul Bakaus", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index ae647c5c8..1798439b6 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "impeccable", - "description": "Design vocabulary and skills for frontend development. Includes 20 skills (19 user-invokable: /polish, /distill, /audit, /typeset, /arrange, etc.) and an enhanced frontend-design skill with curated anti-patterns.", + "description": "Design vocabulary and skills for frontend development. Includes 21 skills (20 user-invokable: /polish, /distill, /audit, /typeset, /overdrive, etc.) and an enhanced frontend-design skill with curated anti-patterns.", "version": "1.3.0", "author": { "name": "Paul Bakaus", diff --git a/.claude/skills/overdrive/SKILL.md b/.claude/skills/overdrive/SKILL.md new file mode 100644 index 000000000..ee0f799b9 --- /dev/null +++ b/.claude/skills/overdrive/SKILL.md @@ -0,0 +1,161 @@ +--- +name: overdrive +description: Add technically extraordinary effects that push the boundaries of what's possible in the browser. WebGPU shaders, scroll-driven animations, generative art, and bleeding-edge APIs — ambitious without gimmicky. +user-invokable: true +args: + - name: target + description: The feature or area to push into overdrive (optional) + required: false +--- + +Push an interface past conventional limits with technically ambitious, visually extraordinary effects that make people stop and ask "how did they do that?" + +## MANDATORY PREPARATION + +Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. + +**EXTRA IMPORTANT FOR THIS SKILL**: Context is everything. A particle system on a creative portfolio is extraordinary. The same particle system on a SaaS settings page is embarrassing. You MUST understand the project's personality, audience, and goals before deciding what's appropriate. + +--- + +## When to Use This (and When Not To) + +This skill is not for every project. Use it when: +- The project's brand rewards boldness and spectacle (creative agencies, games, music, art, portfolios) +- There's a specific moment that should feel extraordinary (launch page, hero section, key transition) +- The audience expects to be impressed (developers, designers, creative professionals) +- The client or team has explicitly asked for something that stands out + +Do NOT use this when: +- The product needs to feel reliable and predictable (banking, healthcare, enterprise tools) +- Performance budgets are tight and every KB counts +- The audience values speed and efficiency over experience (dashboards, admin panels) +- You're adding complexity to compensate for weak fundamentals — fix those with other skills first + +**The test**: Would a senior creative director at a top agency look at this and nod approvingly, or roll their eyes? If the latter, dial it back. + +## Assess the Opportunity + +Before adding anything, understand what moment deserves the investment: + +1. **Find the hero moment**: Not everything can be extraordinary — pick ONE moment that gets the full treatment. A page load. A state transition. A scroll reveal. A hover interaction. Restraint in choosing where to go big is what separates impressive from gimmicky. + +2. **Match the ambition to the brand**: A glitch shader fits a music visualizer. A fluid simulation fits an environmental nonprofit. A generative mesh fits a creative tool. The effect should feel like it *belongs* to this product, not like it was bolted on. + +3. **Check the technical floor**: What browsers does this need to support? What devices? Progressive enhancement is non-negotiable — the experience must work without the effect, and the effect must enhance rather than replace. + +## The Toolkit + +These are the technologies that enable extraordinary interfaces. Choose based on what the moment needs, not what's newest. + +### CSS Bleeding Edge +- **Scroll-driven animations** (`animation-timeline: scroll()`) — tie any animation to scroll position without JavaScript +- **View Transitions API** — cinematic page transitions with shared element morphing +- **`@property`** — register custom properties for animatable gradients, colors, and complex values +- **Anchor positioning** — CSS-native popovers and tooltips that follow elements +- **CSS Houdini** (`paint()` worklets) — custom rendering directly in CSS +- **Container style queries** — style children based on parent's custom property values + +### WebGL / WebGPU +- **Shader effects** — noise distortion, chromatic aberration, liquid effects, ray marching +- **Post-processing** — bloom, depth of field, film grain on 3D or 2D content +- **Particle systems** — reactive particles, cursor trails, ambient atmosphere +- **Libraries**: Three.js, OGL (lightweight), regl, gpu-curtains (DOM + WebGL blend) + +### SVG & Canvas +- **Generative art** — algorithmic patterns, organic shapes, procedural textures +- **SVG filter chains** — displacement maps, turbulence, morphology for organic effects +- **Canvas 2D** — pixel manipulation, custom rendering, performance-critical 2D +- **Lottie / Rive** — vector animations with interactive state machines + +### Advanced Motion +- **FLIP animations** — layout animations at 60fps (First, Last, Invert, Play) +- **Spring physics** — natural motion with mass, tension, damping instead of cubic-bezier +- **Orchestrated sequences** — coordinated multi-element choreography with precise timing +- **Scroll snapping + scroll-driven** — hybrid scroll experiences with momentum + +### Audio & Haptics +- **Web Audio API** — reactive visualizations, spatial audio, sonic feedback +- **Haptic feedback** — `navigator.vibrate()` for tactile responses on mobile +- **Audio-reactive visuals** — effects that respond to music or ambient sound + +## Implement with Discipline + +### Progressive Enhancement is Non-Negotiable + +Every effect MUST degrade gracefully: + +```css +/* Feature detection first */ +@supports (animation-timeline: scroll()) { + .hero { animation-timeline: scroll(); } +} + +/* GPU capability check */ +@media (prefers-reduced-motion: no-preference) { + .shader-bg { /* only show if motion is OK */ } +} +``` + +```javascript +// Always check before using bleeding-edge APIs +if ('gpu' in navigator) { + // WebGPU path +} else if (canvas.getContext('webgl2')) { + // WebGL fallback +} else { + // CSS-only fallback — still must look good +} +``` + +### Performance is the Constraint + +Extraordinary effects that cause jank are worse than no effects at all. + +- **GPU-only**: Effects should run on the GPU. If it touches the main thread per frame, rethink. +- **Budget your frames**: Target 60fps. If you're dropping below 50, simplify. +- **Respect `prefers-reduced-motion`**: Always. No exceptions. Provide a beautiful static alternative. +- **Lazy initialization**: Don't load WebGL/WebGPU until the element is near viewport. +- **Kill off-screen**: Pause rendering when elements scroll out of view. + +### Quality Over Quantity + +- **One extraordinary moment** beats five mediocre effects +- **Polish relentlessly** — the difference between "cool" and "extraordinary" is in the final 20% of refinement: easing curves, timing, color grading, subtle secondary motion +- **Test on real devices** — effects that look amazing on a MacBook Pro might crawl on a mid-range Android + +## The Line Between Extraordinary and Gimmicky + +**Extraordinary:** +- Serves the narrative or emotional arc of the experience +- Feels integrated, like the interface couldn't exist without it +- Makes the user feel something (awe, delight, curiosity) +- Works WITH the content, not on top of it + +**Gimmicky:** +- Exists to demonstrate a technology, not to serve the user +- Feels bolted on — could be removed and nothing would change +- Distracts from the content it's supposed to enhance +- Prioritizes initial "wow" over sustained experience + +When in doubt, ask: **"If I removed this effect, would the experience feel incomplete, or would nobody notice?"** If nobody would notice, it's decoration. If it would feel incomplete, it's design. + +**NEVER**: +- Add effects that can't be turned off or reduced +- Ignore `prefers-reduced-motion` — this is an accessibility requirement, not a suggestion +- Ship effects that drop below 50fps on mid-range devices +- Use WebGPU/WebGL without a meaningful CSS fallback +- Add multiple competing effects — choose ONE hero moment +- Use effects to mask weak design fundamentals — fix those first with other skills +- Add sound without explicit user opt-in + +## Verify the Result + +- **The jaw-drop test**: Show it to someone who hasn't seen it. Do they react? +- **The removal test**: Remove the effect. Does the experience feel diminished? +- **The device test**: Run it on a phone, a tablet, a slow laptop. Still smooth? +- **The accessibility test**: Enable reduced motion. Is the fallback still beautiful? +- **The context test**: Does this effect make sense for THIS brand and audience? +- **The longevity test**: Will this still feel fresh in 6 months, or is it a trend? + +Remember: The goal isn't to use every API in the browser. It's to find the ONE technically ambitious idea that makes this specific interface unforgettable, then execute it with absolute precision. \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 3119602a7..60e29e45c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # Impeccable -The vocabulary you didn't know you needed. 1 skill, 19 commands, and curated anti-patterns for impeccable style. Works with Cursor, Claude Code, Gemini CLI, and Codex CLI. +The vocabulary you didn't know you needed. 1 skill, 20 commands, and curated anti-patterns for impeccable style. Works with Cursor, Claude Code, Gemini CLI, and Codex CLI. ## Repository Purpose diff --git a/NOTICE.md b/NOTICE.md index c74d45c23..ddf948fa0 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -13,5 +13,5 @@ The `frontend-design` skill in this project builds on Anthropic's original front This project extends the original with: - 7 domain-specific reference files (typography, color-and-contrast, spatial-design, motion-design, interaction-design, responsive-design, ux-writing) -- 19 steering commands +- 20 steering commands - Expanded patterns and anti-patterns diff --git a/README.md b/README.md index fa200af4d..37c942024 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Impeccable -The vocabulary you didn't know you needed. 1 skill, 19 commands, and curated anti-patterns for impeccable frontend design. +The vocabulary you didn't know you needed. 1 skill, 20 commands, and curated anti-patterns for impeccable frontend design. > **Quick start:** Visit [impeccable.style](https://impeccable.style) to download ready-to-use bundles. @@ -12,7 +12,7 @@ Every LLM learned from the same generic templates. Without guidance, you get the Impeccable fights that bias with: - **An expanded skill** with 7 domain-specific reference files ([view source](source/skills/frontend-design/)) -- **19 steering commands** to audit, review, polish, distill, animate, and more +- **20 steering commands** to audit, review, polish, distill, animate, and more - **Curated anti-patterns** that explicitly tell the AI what NOT to do ## What's Included @@ -31,7 +31,7 @@ A comprehensive design skill with 7 domain-specific references ([view skill](sou | [responsive-design](source/skills/frontend-design/reference/responsive-design.md) | Mobile-first, fluid design, container queries | | [ux-writing](source/skills/frontend-design/reference/ux-writing.md) | Button labels, error messages, empty states | -### 19 Commands +### 20 Commands | Command | What it does | |---------|--------------| @@ -54,6 +54,7 @@ A comprehensive design skill with 7 domain-specific references ([view skill](sou | `/onboard` | Design onboarding flows | | `/typeset` | Fix font choices, hierarchy, sizing | | `/arrange` | Fix layout, spacing, visual rhythm | +| `/overdrive` | Add technically extraordinary effects | ### Anti-Patterns diff --git a/public/cheatsheet.html b/public/cheatsheet.html index 094b782f4..0f0d4d7b6 100644 --- a/public/cheatsheet.html +++ b/public/cheatsheet.html @@ -4,7 +4,7 @@ Impeccable Command Cheatsheet - + @@ -160,7 +160,7 @@

Impeccable Commands

-

Quick reference for all 19 design commands

+

Quick reference for all 20 design commands

← Back to impeccable.style
@@ -203,7 +203,8 @@ 'adapt': 'adaptation', 'onboard': 'enhancement', 'typeset': 'enhancement', - 'arrange': 'enhancement' + 'arrange': 'enhancement', + 'overdrive': 'enhancement' }; const commandRelationships = { @@ -225,7 +226,8 @@ 'adapt': { combinesWith: ['normalize', 'clarify'], flow: 'Different devices/contexts' }, 'onboard': { combinesWith: ['clarify', 'delight'], flow: 'Onboarding & empty states' }, 'typeset': { combinesWith: ['bolder', 'normalize'], flow: 'Fix typography' }, - 'arrange': { combinesWith: ['distill', 'adapt'], flow: 'Fix layout & spacing' } + 'arrange': { combinesWith: ['distill', 'adapt'], flow: 'Fix layout & spacing' }, + 'overdrive': { combinesWith: ['animate', 'delight'], flow: 'Technically extraordinary effects' } }; async function loadCommands() { diff --git a/public/index.html b/public/index.html index bcbf78be0..c5d00baa4 100644 --- a/public/index.html +++ b/public/index.html @@ -4,7 +4,7 @@ Impeccable: The missing upgrade to Anthropic's frontend-design skill - + @@ -12,7 +12,7 @@ - + @@ -20,7 +20,7 @@ - + @@ -57,7 +57,7 @@
Enhanced frontend-design skill + anti-patterns · - 19 design skills: /polish, /audit, /typeset, /arrange... + 20 design skills: /polish, /audit, /typeset, /overdrive...
@@ -162,7 +162,7 @@

The Framework

-

One comprehensive skill with deep expertise, plus 19 commands that form the language of design.

+

One comprehensive skill with deep expertise, plus 20 commands that form the language of design.

diff --git a/public/js/components/framework-viz.js b/public/js/components/framework-viz.js index a20455872..f2850250d 100644 --- a/public/js/components/framework-viz.js +++ b/public/js/components/framework-viz.js @@ -44,7 +44,8 @@ const commandSymbols = { quieter: 'Qu', onboard: 'On', typeset: 'Ty', - arrange: 'Ar' + arrange: 'Ar', + overdrive: 'Od' }; // Atomic numbers (just for visual interest) @@ -67,7 +68,8 @@ const commandNumbers = { quieter: 15, onboard: 16, typeset: 17, - arrange: 18 + arrange: 18, + overdrive: 19 }; export class PeriodicTable { diff --git a/public/js/data.js b/public/js/data.js index 2e0c49cde..dc1d2de62 100644 --- a/public/js/data.js +++ b/public/js/data.js @@ -55,7 +55,8 @@ export const commandProcessSteps = { 'adapt': ['Analyze', 'Adjust', 'Optimize'], 'onboard': ['Map', 'Design', 'Guide'], 'typeset': ['Assess', 'Select', 'Scale', 'Refine'], - 'arrange': ['Assess', 'Grid', 'Rhythm', 'Balance'] + 'arrange': ['Assess', 'Grid', 'Rhythm', 'Balance'], + 'overdrive': ['Assess', 'Choose', 'Build', 'Polish'] }; export const commandCategories = { @@ -77,7 +78,8 @@ export const commandCategories = { 'adapt': 'adaptation', 'onboard': 'enhancement', 'typeset': 'enhancement', - 'arrange': 'enhancement' + 'arrange': 'enhancement', + 'overdrive': 'enhancement' }; // Skill relationships - now consolidated into frontend-design skill @@ -108,6 +110,7 @@ export const commandRelationships = { 'adapt': { combinesWith: ['normalize', 'clarify'], flow: 'Adaptation: Different devices/contexts' }, 'onboard': { combinesWith: ['clarify', 'delight'], flow: 'Enhancement: Onboarding & empty states' }, 'typeset': { combinesWith: ['bolder', 'normalize'], flow: 'Enhancement: Fix typography' }, - 'arrange': { combinesWith: ['distill', 'adapt'], flow: 'Enhancement: Fix layout & spacing' } + 'arrange': { combinesWith: ['distill', 'adapt'], flow: 'Enhancement: Fix layout & spacing' }, + 'overdrive': { combinesWith: ['animate', 'delight'], flow: 'Enhancement: Technically extraordinary effects' } }; diff --git a/public/js/demos/commands/index.js b/public/js/demos/commands/index.js index f57744725..6be37758e 100644 --- a/public/js/demos/commands/index.js +++ b/public/js/demos/commands/index.js @@ -18,6 +18,7 @@ import adapt from "./adapt.js"; import onboard from "./onboard.js"; import typeset from "./typeset.js"; import arrange from "./arrange.js"; +import overdrive from "./overdrive.js"; export const commandDemos = { normalize, @@ -38,6 +39,7 @@ export const commandDemos = { onboard, typeset, arrange, + overdrive, }; export function getCommandDemo(commandId) { diff --git a/public/js/demos/commands/overdrive.js b/public/js/demos/commands/overdrive.js new file mode 100644 index 000000000..5eb7a0fd3 --- /dev/null +++ b/public/js/demos/commands/overdrive.js @@ -0,0 +1,31 @@ +// Overdrive command demo - shows conventional UI becoming technically extraordinary +export default { + id: 'overdrive', + caption: 'Conventional static hero → Technically extraordinary experience', + + before: ` +
+
INTRODUCING
+
Nova Engine
+

The next generation of creative tools.

+ +
+ `, + + after: ` +
+
+
+
+
INTRODUCING
+
Nova Engine
+

The next generation of creative tools.

+ +
+ +
+ ` +}; diff --git a/source/skills/overdrive/SKILL.md b/source/skills/overdrive/SKILL.md new file mode 100644 index 000000000..950764942 --- /dev/null +++ b/source/skills/overdrive/SKILL.md @@ -0,0 +1,161 @@ +--- +name: overdrive +description: Add technically extraordinary effects that push the boundaries of what's possible in the browser. WebGPU shaders, scroll-driven animations, generative art, and bleeding-edge APIs — ambitious without gimmicky. +args: + - name: target + description: The feature or area to push into overdrive (optional) + required: false +user-invokable: true +--- + +Push an interface past conventional limits with technically ambitious, visually extraordinary effects that make people stop and ask "how did they do that?" + +## MANDATORY PREPARATION + +Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. + +**EXTRA IMPORTANT FOR THIS SKILL**: Context is everything. A particle system on a creative portfolio is extraordinary. The same particle system on a SaaS settings page is embarrassing. You MUST understand the project's personality, audience, and goals before deciding what's appropriate. + +--- + +## When to Use This (and When Not To) + +This skill is not for every project. Use it when: +- The project's brand rewards boldness and spectacle (creative agencies, games, music, art, portfolios) +- There's a specific moment that should feel extraordinary (launch page, hero section, key transition) +- The audience expects to be impressed (developers, designers, creative professionals) +- The client or team has explicitly asked for something that stands out + +Do NOT use this when: +- The product needs to feel reliable and predictable (banking, healthcare, enterprise tools) +- Performance budgets are tight and every KB counts +- The audience values speed and efficiency over experience (dashboards, admin panels) +- You're adding complexity to compensate for weak fundamentals — fix those with other skills first + +**The test**: Would a senior creative director at a top agency look at this and nod approvingly, or roll their eyes? If the latter, dial it back. + +## Assess the Opportunity + +Before adding anything, understand what moment deserves the investment: + +1. **Find the hero moment**: Not everything can be extraordinary — pick ONE moment that gets the full treatment. A page load. A state transition. A scroll reveal. A hover interaction. Restraint in choosing where to go big is what separates impressive from gimmicky. + +2. **Match the ambition to the brand**: A glitch shader fits a music visualizer. A fluid simulation fits an environmental nonprofit. A generative mesh fits a creative tool. The effect should feel like it *belongs* to this product, not like it was bolted on. + +3. **Check the technical floor**: What browsers does this need to support? What devices? Progressive enhancement is non-negotiable — the experience must work without the effect, and the effect must enhance rather than replace. + +## The Toolkit + +These are the technologies that enable extraordinary interfaces. Choose based on what the moment needs, not what's newest. + +### CSS Bleeding Edge +- **Scroll-driven animations** (`animation-timeline: scroll()`) — tie any animation to scroll position without JavaScript +- **View Transitions API** — cinematic page transitions with shared element morphing +- **`@property`** — register custom properties for animatable gradients, colors, and complex values +- **Anchor positioning** — CSS-native popovers and tooltips that follow elements +- **CSS Houdini** (`paint()` worklets) — custom rendering directly in CSS +- **Container style queries** — style children based on parent's custom property values + +### WebGL / WebGPU +- **Shader effects** — noise distortion, chromatic aberration, liquid effects, ray marching +- **Post-processing** — bloom, depth of field, film grain on 3D or 2D content +- **Particle systems** — reactive particles, cursor trails, ambient atmosphere +- **Libraries**: Three.js, OGL (lightweight), regl, gpu-curtains (DOM + WebGL blend) + +### SVG & Canvas +- **Generative art** — algorithmic patterns, organic shapes, procedural textures +- **SVG filter chains** — displacement maps, turbulence, morphology for organic effects +- **Canvas 2D** — pixel manipulation, custom rendering, performance-critical 2D +- **Lottie / Rive** — vector animations with interactive state machines + +### Advanced Motion +- **FLIP animations** — layout animations at 60fps (First, Last, Invert, Play) +- **Spring physics** — natural motion with mass, tension, damping instead of cubic-bezier +- **Orchestrated sequences** — coordinated multi-element choreography with precise timing +- **Scroll snapping + scroll-driven** — hybrid scroll experiences with momentum + +### Audio & Haptics +- **Web Audio API** — reactive visualizations, spatial audio, sonic feedback +- **Haptic feedback** — `navigator.vibrate()` for tactile responses on mobile +- **Audio-reactive visuals** — effects that respond to music or ambient sound + +## Implement with Discipline + +### Progressive Enhancement is Non-Negotiable + +Every effect MUST degrade gracefully: + +```css +/* Feature detection first */ +@supports (animation-timeline: scroll()) { + .hero { animation-timeline: scroll(); } +} + +/* GPU capability check */ +@media (prefers-reduced-motion: no-preference) { + .shader-bg { /* only show if motion is OK */ } +} +``` + +```javascript +// Always check before using bleeding-edge APIs +if ('gpu' in navigator) { + // WebGPU path +} else if (canvas.getContext('webgl2')) { + // WebGL fallback +} else { + // CSS-only fallback — still must look good +} +``` + +### Performance is the Constraint + +Extraordinary effects that cause jank are worse than no effects at all. + +- **GPU-only**: Effects should run on the GPU. If it touches the main thread per frame, rethink. +- **Budget your frames**: Target 60fps. If you're dropping below 50, simplify. +- **Respect `prefers-reduced-motion`**: Always. No exceptions. Provide a beautiful static alternative. +- **Lazy initialization**: Don't load WebGL/WebGPU until the element is near viewport. +- **Kill off-screen**: Pause rendering when elements scroll out of view. + +### Quality Over Quantity + +- **One extraordinary moment** beats five mediocre effects +- **Polish relentlessly** — the difference between "cool" and "extraordinary" is in the final 20% of refinement: easing curves, timing, color grading, subtle secondary motion +- **Test on real devices** — effects that look amazing on a MacBook Pro might crawl on a mid-range Android + +## The Line Between Extraordinary and Gimmicky + +**Extraordinary:** +- Serves the narrative or emotional arc of the experience +- Feels integrated, like the interface couldn't exist without it +- Makes the user feel something (awe, delight, curiosity) +- Works WITH the content, not on top of it + +**Gimmicky:** +- Exists to demonstrate a technology, not to serve the user +- Feels bolted on — could be removed and nothing would change +- Distracts from the content it's supposed to enhance +- Prioritizes initial "wow" over sustained experience + +When in doubt, ask: **"If I removed this effect, would the experience feel incomplete, or would nobody notice?"** If nobody would notice, it's decoration. If it would feel incomplete, it's design. + +**NEVER**: +- Add effects that can't be turned off or reduced +- Ignore `prefers-reduced-motion` — this is an accessibility requirement, not a suggestion +- Ship effects that drop below 50fps on mid-range devices +- Use WebGPU/WebGL without a meaningful CSS fallback +- Add multiple competing effects — choose ONE hero moment +- Use effects to mask weak design fundamentals — fix those first with other skills +- Add sound without explicit user opt-in + +## Verify the Result + +- **The jaw-drop test**: Show it to someone who hasn't seen it. Do they react? +- **The removal test**: Remove the effect. Does the experience feel diminished? +- **The device test**: Run it on a phone, a tablet, a slow laptop. Still smooth? +- **The accessibility test**: Enable reduced motion. Is the fallback still beautiful? +- **The context test**: Does this effect make sense for THIS brand and audience? +- **The longevity test**: Will this still feel fresh in 6 months, or is it a trend? + +Remember: The goal isn't to use every API in the browser. It's to find the ONE technically ambitious idea that makes this specific interface unforgettable, then execute it with absolute precision. From 234f5b70510f33caa51e14e690f940875a112bed Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Sun, 15 Mar 2026 20:08:15 -0700 Subject: [PATCH 05/14] Rewrite /overdrive skill from scratch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original was an effects-only skill biased toward creative portfolios and visual spectacle. The rewrite addresses: 1. Scope: now covers ALL forms of technical ambition — performance (virtual scrolling, WASM, Web Workers), interaction patterns (View Transitions on dialogs, spring physics), real-time collab (WebSockets, SharedArrayBuffer), and data visualization — not just shaders and particles. 2. Browser support: removed Houdini Paint API (Chromium-only), removed navigator.vibrate() (Safari never shipped, Firefox dropped), added support notes for each technology tier. 3. Bias corrections: removed creative-portfolio-only framing, removed "pick ONE hero moment" dogma, added examples for functional UI (tables, forms, dialogs) and app architecture. 4. Structure: organized toolkit by what you're trying to achieve (make transitions cinematic, push performance boundaries) not by technology name. 5. Demo: replaced purple gradient AI slop with a structural before/after showing view-transition-name on project cards. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/overdrive/SKILL.md | 175 +++++++++++--------------- public/js/demos/commands/overdrive.js | 58 ++++++--- source/skills/overdrive/SKILL.md | 175 +++++++++++--------------- 3 files changed, 179 insertions(+), 229 deletions(-) diff --git a/.claude/skills/overdrive/SKILL.md b/.claude/skills/overdrive/SKILL.md index ee0f799b9..d90660d63 100644 --- a/.claude/skills/overdrive/SKILL.md +++ b/.claude/skills/overdrive/SKILL.md @@ -1,6 +1,6 @@ --- name: overdrive -description: Add technically extraordinary effects that push the boundaries of what's possible in the browser. WebGPU shaders, scroll-driven animations, generative art, and bleeding-edge APIs — ambitious without gimmicky. +description: Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or real-time collaboration — make users ask "how did they do that?" user-invokable: true args: - name: target @@ -8,154 +8,119 @@ args: required: false --- -Push an interface past conventional limits with technically ambitious, visually extraordinary effects that make people stop and ask "how did they do that?" +Push an interface past conventional limits. This isn't just about visual effects — it's about using the full power of the browser to make any part of an interface feel extraordinary: a table that handles a million rows, a dialog that morphs from its trigger, a form that validates in real-time with streaming feedback, a page transition that feels cinematic. ## MANDATORY PREPARATION Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. -**EXTRA IMPORTANT FOR THIS SKILL**: Context is everything. A particle system on a creative portfolio is extraordinary. The same particle system on a SaaS settings page is embarrassing. You MUST understand the project's personality, audience, and goals before deciding what's appropriate. +**EXTRA IMPORTANT FOR THIS SKILL**: Context determines what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate. --- -## When to Use This (and When Not To) +## Assess What "Extraordinary" Means Here -This skill is not for every project. Use it when: -- The project's brand rewards boldness and spectacle (creative agencies, games, music, art, portfolios) -- There's a specific moment that should feel extraordinary (launch page, hero section, key transition) -- The audience expects to be impressed (developers, designers, creative professionals) -- The client or team has explicitly asked for something that stands out +The right kind of technical ambition depends entirely on what you're working with. Before choosing a technique, ask: **what would make a user of THIS specific interface say "wow, that's nice"?** -Do NOT use this when: -- The product needs to feel reliable and predictable (banking, healthcare, enterprise tools) -- Performance budgets are tight and every KB counts -- The audience values speed and efficiency over experience (dashboards, admin panels) -- You're adding complexity to compensate for weak fundamentals — fix those with other skills first +### For visual/marketing surfaces +Pages, hero sections, landing pages, portfolios — the "wow" is often sensory: a scroll-driven reveal, a shader background, a cinematic page transition, generative art that responds to the cursor. -**The test**: Would a senior creative director at a top agency look at this and nod approvingly, or roll their eyes? If the latter, dial it back. +### For functional UI +Tables, forms, dialogs, navigation — the "wow" is in how it FEELS: a dialog that morphs from the button that triggered it via View Transitions, a data table that renders 100k rows at 60fps via virtual scrolling, a form with streaming validation that feels instant, drag-and-drop with spring physics. -## Assess the Opportunity +### For application architecture +The "wow" is invisible but felt: offline-first with service workers (the app works on a plane), real-time collaboration (cursors appearing as someone else types), near-native computation via WASM, background processing via Web Workers that never blocks the UI. -Before adding anything, understand what moment deserves the investment: +### For data-heavy interfaces +Charts and dashboards — the "wow" is in fluidity: GPU-accelerated rendering via Canvas/WebGL for massive datasets, animated transitions between data states, force-directed graph layouts that settle naturally. -1. **Find the hero moment**: Not everything can be extraordinary — pick ONE moment that gets the full treatment. A page load. A state transition. A scroll reveal. A hover interaction. Restraint in choosing where to go big is what separates impressive from gimmicky. - -2. **Match the ambition to the brand**: A glitch shader fits a music visualizer. A fluid simulation fits an environmental nonprofit. A generative mesh fits a creative tool. The effect should feel like it *belongs* to this product, not like it was bolted on. - -3. **Check the technical floor**: What browsers does this need to support? What devices? Progressive enhancement is non-negotiable — the experience must work without the effect, and the effect must enhance rather than replace. +**The common thread**: something about the implementation goes beyond what users expect from a web interface. The technique serves the experience, not the other way around. ## The Toolkit -These are the technologies that enable extraordinary interfaces. Choose based on what the moment needs, not what's newest. +Organized by what you're trying to achieve, not by technology name. -### CSS Bleeding Edge -- **Scroll-driven animations** (`animation-timeline: scroll()`) — tie any animation to scroll position without JavaScript -- **View Transitions API** — cinematic page transitions with shared element morphing -- **`@property`** — register custom properties for animatable gradients, colors, and complex values -- **Anchor positioning** — CSS-native popovers and tooltips that follow elements -- **CSS Houdini** (`paint()` worklets) — custom rendering directly in CSS -- **Container style queries** — style children based on parent's custom property values +### Make transitions feel cinematic +- **View Transitions API** (same-document: all browsers; cross-document: no Firefox) — shared element morphing between states. A list item expanding into a detail page. A button morphing into a dialog. This is the closest thing to native FLIP animations. +- **`@starting-style`** (all browsers) — animate elements from `display: none` to visible with CSS only, including entry keyframes +- **Spring physics** — natural motion with mass, tension, and damping instead of cubic-bezier. Libraries: motion (formerly Framer Motion), GSAP, or roll your own spring solver. -### WebGL / WebGPU -- **Shader effects** — noise distortion, chromatic aberration, liquid effects, ray marching -- **Post-processing** — bloom, depth of field, film grain on 3D or 2D content -- **Particle systems** — reactive particles, cursor trails, ambient atmosphere -- **Libraries**: Three.js, OGL (lightweight), regl, gpu-curtains (DOM + WebGL blend) +### Tie animation to scroll position +- **Scroll-driven animations** (`animation-timeline: scroll()`) — CSS-only, no JS. Parallax, progress bars, reveal sequences all driven by scroll position. (Chrome/Edge/Safari; Firefox: flag only — always provide a static fallback) -### SVG & Canvas -- **Generative art** — algorithmic patterns, organic shapes, procedural textures -- **SVG filter chains** — displacement maps, turbulence, morphology for organic effects -- **Canvas 2D** — pixel manipulation, custom rendering, performance-critical 2D -- **Lottie / Rive** — vector animations with interactive state machines +### Render beyond CSS +- **WebGL** (all browsers) — shader effects, post-processing, particle systems. Libraries: Three.js, OGL (lightweight), regl. Use for effects CSS can't express. +- **WebGPU** (Chrome/Edge; Safari partial; Firefox: flag only) — next-gen GPU compute. More powerful than WebGL but limited browser support. Always fall back to WebGL2. +- **Canvas 2D / OffscreenCanvas** — custom rendering, pixel manipulation, or moving heavy rendering off the main thread entirely via Web Workers + OffscreenCanvas. +- **SVG filter chains** — displacement maps, turbulence, morphology for organic distortion effects. CSS-animatable. -### Advanced Motion -- **FLIP animations** — layout animations at 60fps (First, Last, Invert, Play) -- **Spring physics** — natural motion with mass, tension, damping instead of cubic-bezier -- **Orchestrated sequences** — coordinated multi-element choreography with precise timing -- **Scroll snapping + scroll-driven** — hybrid scroll experiences with momentum +### Make data feel alive +- **Virtual scrolling** — render only visible rows for tables/lists with tens of thousands of items. No library required for simple cases; TanStack Virtual for complex ones. +- **GPU-accelerated charts** — Canvas or WebGL-rendered data visualization for datasets too large for SVG/DOM. Libraries: deck.gl, regl-based custom renderers. +- **Animated data transitions** — morph between chart states rather than replacing. D3's `transition()` or View Transitions for DOM-based charts. -### Audio & Haptics -- **Web Audio API** — reactive visualizations, spatial audio, sonic feedback -- **Haptic feedback** — `navigator.vibrate()` for tactile responses on mobile -- **Audio-reactive visuals** — effects that respond to music or ambient sound +### Animate complex properties +- **`@property`** (all browsers) — register custom CSS properties with types, enabling animation of gradients, colors, and complex values that CSS can't normally interpolate. +- **Web Animations API** (all browsers) — JavaScript-driven animations with the performance of CSS. Composable, cancellable, reversible. The foundation for complex choreography. + +### Push performance boundaries +- **Web Workers** — move computation off the main thread. Heavy data processing, image manipulation, search indexing — anything that would cause jank. +- **OffscreenCanvas** — render in a Worker thread. The main thread stays free while complex visuals render in the background. +- **WASM** — near-native performance for computation-heavy features. Image processing, encryption, physics simulations, codecs. +- **Service Workers** — offline-first experiences, background sync, push notifications. The app works without a network. + +### Enable real-time collaboration +- **WebSockets / SSE** — live cursors, collaborative editing, streaming updates. The interface feels alive. +- **SharedArrayBuffer** — shared memory between threads for high-performance real-time data. + +### Interact with the device +- **Web Audio API** — spatial audio, audio-reactive visualizations, sonic feedback. Requires user gesture to start. +- **Device APIs** — orientation, ambient light, geolocation. Use sparingly and always with user permission. ## Implement with Discipline -### Progressive Enhancement is Non-Negotiable +### Progressive enhancement is non-negotiable -Every effect MUST degrade gracefully: +Every technique must degrade gracefully. The experience without the enhancement must still be good. ```css -/* Feature detection first */ @supports (animation-timeline: scroll()) { .hero { animation-timeline: scroll(); } } - -/* GPU capability check */ -@media (prefers-reduced-motion: no-preference) { - .shader-bg { /* only show if motion is OK */ } -} ``` ```javascript -// Always check before using bleeding-edge APIs -if ('gpu' in navigator) { - // WebGPU path -} else if (canvas.getContext('webgl2')) { - // WebGL fallback -} else { - // CSS-only fallback — still must look good -} +if ('gpu' in navigator) { /* WebGPU */ } +else if (canvas.getContext('webgl2')) { /* WebGL2 fallback */ } +/* CSS-only fallback must still look good */ ``` -### Performance is the Constraint +### Performance rules -Extraordinary effects that cause jank are worse than no effects at all. +- Target 60fps. If dropping below 50, simplify. +- Respect `prefers-reduced-motion` — always. Provide a beautiful static alternative. +- Lazy-initialize heavy resources (WebGL contexts, WASM modules) only when near viewport. +- Pause off-screen rendering. Kill what you can't see. +- Test on real mid-range devices, not just your development machine. -- **GPU-only**: Effects should run on the GPU. If it touches the main thread per frame, rethink. -- **Budget your frames**: Target 60fps. If you're dropping below 50, simplify. -- **Respect `prefers-reduced-motion`**: Always. No exceptions. Provide a beautiful static alternative. -- **Lazy initialization**: Don't load WebGL/WebGPU until the element is near viewport. -- **Kill off-screen**: Pause rendering when elements scroll out of view. +### Polish is the difference -### Quality Over Quantity - -- **One extraordinary moment** beats five mediocre effects -- **Polish relentlessly** — the difference between "cool" and "extraordinary" is in the final 20% of refinement: easing curves, timing, color grading, subtle secondary motion -- **Test on real devices** — effects that look amazing on a MacBook Pro might crawl on a mid-range Android - -## The Line Between Extraordinary and Gimmicky - -**Extraordinary:** -- Serves the narrative or emotional arc of the experience -- Feels integrated, like the interface couldn't exist without it -- Makes the user feel something (awe, delight, curiosity) -- Works WITH the content, not on top of it - -**Gimmicky:** -- Exists to demonstrate a technology, not to serve the user -- Feels bolted on — could be removed and nothing would change -- Distracts from the content it's supposed to enhance -- Prioritizes initial "wow" over sustained experience - -When in doubt, ask: **"If I removed this effect, would the experience feel incomplete, or would nobody notice?"** If nobody would notice, it's decoration. If it would feel incomplete, it's design. +The gap between "cool" and "extraordinary" is in the last 20% of refinement: the easing curve on a spring animation, the timing offset in a staggered reveal, the subtle secondary motion that makes a transition feel physical. Don't ship the first version that works — ship the version that feels inevitable. **NEVER**: -- Add effects that can't be turned off or reduced - Ignore `prefers-reduced-motion` — this is an accessibility requirement, not a suggestion -- Ship effects that drop below 50fps on mid-range devices -- Use WebGPU/WebGL without a meaningful CSS fallback -- Add multiple competing effects — choose ONE hero moment -- Use effects to mask weak design fundamentals — fix those first with other skills +- Ship effects that cause jank on mid-range devices +- Use bleeding-edge APIs without a functional fallback - Add sound without explicit user opt-in +- Use technical ambition to mask weak design fundamentals — fix those first with other skills +- Layer multiple competing extraordinary moments — focus creates impact, excess creates noise ## Verify the Result -- **The jaw-drop test**: Show it to someone who hasn't seen it. Do they react? -- **The removal test**: Remove the effect. Does the experience feel diminished? -- **The device test**: Run it on a phone, a tablet, a slow laptop. Still smooth? -- **The accessibility test**: Enable reduced motion. Is the fallback still beautiful? -- **The context test**: Does this effect make sense for THIS brand and audience? -- **The longevity test**: Will this still feel fresh in 6 months, or is it a trend? +- **The wow test**: Show it to someone who hasn't seen it. Do they react? +- **The removal test**: Take it away. Does the experience feel diminished, or does nobody notice? +- **The device test**: Run it on a phone, a tablet, a Chromebook. Still smooth? +- **The accessibility test**: Enable reduced motion. Still beautiful? +- **The context test**: Does this make sense for THIS brand and audience? -Remember: The goal isn't to use every API in the browser. It's to find the ONE technically ambitious idea that makes this specific interface unforgettable, then execute it with absolute precision. \ No newline at end of file +Remember: "Technically extraordinary" isn't about using the newest API. It's about making an interface do something users didn't think a website could do. \ No newline at end of file diff --git a/public/js/demos/commands/overdrive.js b/public/js/demos/commands/overdrive.js index 5eb7a0fd3..315b397d8 100644 --- a/public/js/demos/commands/overdrive.js +++ b/public/js/demos/commands/overdrive.js @@ -1,31 +1,51 @@ -// Overdrive command demo - shows conventional UI becoming technically extraordinary +// Overdrive command demo - shows a static list becoming a morphing shared-element transition export default { id: 'overdrive', - caption: 'Conventional static hero → Technically extraordinary experience', + caption: 'Static list with page jump → Shared element morph transition', before: ` -
-
INTRODUCING
-
Nova Engine
-

The next generation of creative tools.

- +
+
PROJECTS
+
+
+
+
+
Redesign
+
3 tasks
+
+
+
+
+
+
Launch
+
7 tasks
+
+
+
`, after: ` -
-
-
-
-
INTRODUCING
-
Nova Engine
-

The next generation of creative tools.

- +
+
PROJECTS
+
+
+
R
+
+
Redesign
+
3 tasks
+
+
Active
+
+
+
L
+
+
Launch
+
7 tasks
+
+
- +
view-transition-name on cards for shared element morphing
` }; diff --git a/source/skills/overdrive/SKILL.md b/source/skills/overdrive/SKILL.md index 950764942..9e2b5a155 100644 --- a/source/skills/overdrive/SKILL.md +++ b/source/skills/overdrive/SKILL.md @@ -1,6 +1,6 @@ --- name: overdrive -description: Add technically extraordinary effects that push the boundaries of what's possible in the browser. WebGPU shaders, scroll-driven animations, generative art, and bleeding-edge APIs — ambitious without gimmicky. +description: Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or real-time collaboration — make users ask "how did they do that?" args: - name: target description: The feature or area to push into overdrive (optional) @@ -8,154 +8,119 @@ args: user-invokable: true --- -Push an interface past conventional limits with technically ambitious, visually extraordinary effects that make people stop and ask "how did they do that?" +Push an interface past conventional limits. This isn't just about visual effects — it's about using the full power of the browser to make any part of an interface feel extraordinary: a table that handles a million rows, a dialog that morphs from its trigger, a form that validates in real-time with streaming feedback, a page transition that feels cinematic. ## MANDATORY PREPARATION Use the frontend-design skill — it contains design principles, anti-patterns, and the **Context Gathering Protocol**. Follow the protocol before proceeding — if no design context exists yet, you MUST run teach-impeccable first. -**EXTRA IMPORTANT FOR THIS SKILL**: Context is everything. A particle system on a creative portfolio is extraordinary. The same particle system on a SaaS settings page is embarrassing. You MUST understand the project's personality, audience, and goals before deciding what's appropriate. +**EXTRA IMPORTANT FOR THIS SKILL**: Context determines what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate. --- -## When to Use This (and When Not To) +## Assess What "Extraordinary" Means Here -This skill is not for every project. Use it when: -- The project's brand rewards boldness and spectacle (creative agencies, games, music, art, portfolios) -- There's a specific moment that should feel extraordinary (launch page, hero section, key transition) -- The audience expects to be impressed (developers, designers, creative professionals) -- The client or team has explicitly asked for something that stands out +The right kind of technical ambition depends entirely on what you're working with. Before choosing a technique, ask: **what would make a user of THIS specific interface say "wow, that's nice"?** -Do NOT use this when: -- The product needs to feel reliable and predictable (banking, healthcare, enterprise tools) -- Performance budgets are tight and every KB counts -- The audience values speed and efficiency over experience (dashboards, admin panels) -- You're adding complexity to compensate for weak fundamentals — fix those with other skills first +### For visual/marketing surfaces +Pages, hero sections, landing pages, portfolios — the "wow" is often sensory: a scroll-driven reveal, a shader background, a cinematic page transition, generative art that responds to the cursor. -**The test**: Would a senior creative director at a top agency look at this and nod approvingly, or roll their eyes? If the latter, dial it back. +### For functional UI +Tables, forms, dialogs, navigation — the "wow" is in how it FEELS: a dialog that morphs from the button that triggered it via View Transitions, a data table that renders 100k rows at 60fps via virtual scrolling, a form with streaming validation that feels instant, drag-and-drop with spring physics. -## Assess the Opportunity +### For application architecture +The "wow" is invisible but felt: offline-first with service workers (the app works on a plane), real-time collaboration (cursors appearing as someone else types), near-native computation via WASM, background processing via Web Workers that never blocks the UI. -Before adding anything, understand what moment deserves the investment: +### For data-heavy interfaces +Charts and dashboards — the "wow" is in fluidity: GPU-accelerated rendering via Canvas/WebGL for massive datasets, animated transitions between data states, force-directed graph layouts that settle naturally. -1. **Find the hero moment**: Not everything can be extraordinary — pick ONE moment that gets the full treatment. A page load. A state transition. A scroll reveal. A hover interaction. Restraint in choosing where to go big is what separates impressive from gimmicky. - -2. **Match the ambition to the brand**: A glitch shader fits a music visualizer. A fluid simulation fits an environmental nonprofit. A generative mesh fits a creative tool. The effect should feel like it *belongs* to this product, not like it was bolted on. - -3. **Check the technical floor**: What browsers does this need to support? What devices? Progressive enhancement is non-negotiable — the experience must work without the effect, and the effect must enhance rather than replace. +**The common thread**: something about the implementation goes beyond what users expect from a web interface. The technique serves the experience, not the other way around. ## The Toolkit -These are the technologies that enable extraordinary interfaces. Choose based on what the moment needs, not what's newest. +Organized by what you're trying to achieve, not by technology name. -### CSS Bleeding Edge -- **Scroll-driven animations** (`animation-timeline: scroll()`) — tie any animation to scroll position without JavaScript -- **View Transitions API** — cinematic page transitions with shared element morphing -- **`@property`** — register custom properties for animatable gradients, colors, and complex values -- **Anchor positioning** — CSS-native popovers and tooltips that follow elements -- **CSS Houdini** (`paint()` worklets) — custom rendering directly in CSS -- **Container style queries** — style children based on parent's custom property values +### Make transitions feel cinematic +- **View Transitions API** (same-document: all browsers; cross-document: no Firefox) — shared element morphing between states. A list item expanding into a detail page. A button morphing into a dialog. This is the closest thing to native FLIP animations. +- **`@starting-style`** (all browsers) — animate elements from `display: none` to visible with CSS only, including entry keyframes +- **Spring physics** — natural motion with mass, tension, and damping instead of cubic-bezier. Libraries: motion (formerly Framer Motion), GSAP, or roll your own spring solver. -### WebGL / WebGPU -- **Shader effects** — noise distortion, chromatic aberration, liquid effects, ray marching -- **Post-processing** — bloom, depth of field, film grain on 3D or 2D content -- **Particle systems** — reactive particles, cursor trails, ambient atmosphere -- **Libraries**: Three.js, OGL (lightweight), regl, gpu-curtains (DOM + WebGL blend) +### Tie animation to scroll position +- **Scroll-driven animations** (`animation-timeline: scroll()`) — CSS-only, no JS. Parallax, progress bars, reveal sequences all driven by scroll position. (Chrome/Edge/Safari; Firefox: flag only — always provide a static fallback) -### SVG & Canvas -- **Generative art** — algorithmic patterns, organic shapes, procedural textures -- **SVG filter chains** — displacement maps, turbulence, morphology for organic effects -- **Canvas 2D** — pixel manipulation, custom rendering, performance-critical 2D -- **Lottie / Rive** — vector animations with interactive state machines +### Render beyond CSS +- **WebGL** (all browsers) — shader effects, post-processing, particle systems. Libraries: Three.js, OGL (lightweight), regl. Use for effects CSS can't express. +- **WebGPU** (Chrome/Edge; Safari partial; Firefox: flag only) — next-gen GPU compute. More powerful than WebGL but limited browser support. Always fall back to WebGL2. +- **Canvas 2D / OffscreenCanvas** — custom rendering, pixel manipulation, or moving heavy rendering off the main thread entirely via Web Workers + OffscreenCanvas. +- **SVG filter chains** — displacement maps, turbulence, morphology for organic distortion effects. CSS-animatable. -### Advanced Motion -- **FLIP animations** — layout animations at 60fps (First, Last, Invert, Play) -- **Spring physics** — natural motion with mass, tension, damping instead of cubic-bezier -- **Orchestrated sequences** — coordinated multi-element choreography with precise timing -- **Scroll snapping + scroll-driven** — hybrid scroll experiences with momentum +### Make data feel alive +- **Virtual scrolling** — render only visible rows for tables/lists with tens of thousands of items. No library required for simple cases; TanStack Virtual for complex ones. +- **GPU-accelerated charts** — Canvas or WebGL-rendered data visualization for datasets too large for SVG/DOM. Libraries: deck.gl, regl-based custom renderers. +- **Animated data transitions** — morph between chart states rather than replacing. D3's `transition()` or View Transitions for DOM-based charts. -### Audio & Haptics -- **Web Audio API** — reactive visualizations, spatial audio, sonic feedback -- **Haptic feedback** — `navigator.vibrate()` for tactile responses on mobile -- **Audio-reactive visuals** — effects that respond to music or ambient sound +### Animate complex properties +- **`@property`** (all browsers) — register custom CSS properties with types, enabling animation of gradients, colors, and complex values that CSS can't normally interpolate. +- **Web Animations API** (all browsers) — JavaScript-driven animations with the performance of CSS. Composable, cancellable, reversible. The foundation for complex choreography. + +### Push performance boundaries +- **Web Workers** — move computation off the main thread. Heavy data processing, image manipulation, search indexing — anything that would cause jank. +- **OffscreenCanvas** — render in a Worker thread. The main thread stays free while complex visuals render in the background. +- **WASM** — near-native performance for computation-heavy features. Image processing, encryption, physics simulations, codecs. +- **Service Workers** — offline-first experiences, background sync, push notifications. The app works without a network. + +### Enable real-time collaboration +- **WebSockets / SSE** — live cursors, collaborative editing, streaming updates. The interface feels alive. +- **SharedArrayBuffer** — shared memory between threads for high-performance real-time data. + +### Interact with the device +- **Web Audio API** — spatial audio, audio-reactive visualizations, sonic feedback. Requires user gesture to start. +- **Device APIs** — orientation, ambient light, geolocation. Use sparingly and always with user permission. ## Implement with Discipline -### Progressive Enhancement is Non-Negotiable +### Progressive enhancement is non-negotiable -Every effect MUST degrade gracefully: +Every technique must degrade gracefully. The experience without the enhancement must still be good. ```css -/* Feature detection first */ @supports (animation-timeline: scroll()) { .hero { animation-timeline: scroll(); } } - -/* GPU capability check */ -@media (prefers-reduced-motion: no-preference) { - .shader-bg { /* only show if motion is OK */ } -} ``` ```javascript -// Always check before using bleeding-edge APIs -if ('gpu' in navigator) { - // WebGPU path -} else if (canvas.getContext('webgl2')) { - // WebGL fallback -} else { - // CSS-only fallback — still must look good -} +if ('gpu' in navigator) { /* WebGPU */ } +else if (canvas.getContext('webgl2')) { /* WebGL2 fallback */ } +/* CSS-only fallback must still look good */ ``` -### Performance is the Constraint +### Performance rules -Extraordinary effects that cause jank are worse than no effects at all. +- Target 60fps. If dropping below 50, simplify. +- Respect `prefers-reduced-motion` — always. Provide a beautiful static alternative. +- Lazy-initialize heavy resources (WebGL contexts, WASM modules) only when near viewport. +- Pause off-screen rendering. Kill what you can't see. +- Test on real mid-range devices, not just your development machine. -- **GPU-only**: Effects should run on the GPU. If it touches the main thread per frame, rethink. -- **Budget your frames**: Target 60fps. If you're dropping below 50, simplify. -- **Respect `prefers-reduced-motion`**: Always. No exceptions. Provide a beautiful static alternative. -- **Lazy initialization**: Don't load WebGL/WebGPU until the element is near viewport. -- **Kill off-screen**: Pause rendering when elements scroll out of view. +### Polish is the difference -### Quality Over Quantity - -- **One extraordinary moment** beats five mediocre effects -- **Polish relentlessly** — the difference between "cool" and "extraordinary" is in the final 20% of refinement: easing curves, timing, color grading, subtle secondary motion -- **Test on real devices** — effects that look amazing on a MacBook Pro might crawl on a mid-range Android - -## The Line Between Extraordinary and Gimmicky - -**Extraordinary:** -- Serves the narrative or emotional arc of the experience -- Feels integrated, like the interface couldn't exist without it -- Makes the user feel something (awe, delight, curiosity) -- Works WITH the content, not on top of it - -**Gimmicky:** -- Exists to demonstrate a technology, not to serve the user -- Feels bolted on — could be removed and nothing would change -- Distracts from the content it's supposed to enhance -- Prioritizes initial "wow" over sustained experience - -When in doubt, ask: **"If I removed this effect, would the experience feel incomplete, or would nobody notice?"** If nobody would notice, it's decoration. If it would feel incomplete, it's design. +The gap between "cool" and "extraordinary" is in the last 20% of refinement: the easing curve on a spring animation, the timing offset in a staggered reveal, the subtle secondary motion that makes a transition feel physical. Don't ship the first version that works — ship the version that feels inevitable. **NEVER**: -- Add effects that can't be turned off or reduced - Ignore `prefers-reduced-motion` — this is an accessibility requirement, not a suggestion -- Ship effects that drop below 50fps on mid-range devices -- Use WebGPU/WebGL without a meaningful CSS fallback -- Add multiple competing effects — choose ONE hero moment -- Use effects to mask weak design fundamentals — fix those first with other skills +- Ship effects that cause jank on mid-range devices +- Use bleeding-edge APIs without a functional fallback - Add sound without explicit user opt-in +- Use technical ambition to mask weak design fundamentals — fix those first with other skills +- Layer multiple competing extraordinary moments — focus creates impact, excess creates noise ## Verify the Result -- **The jaw-drop test**: Show it to someone who hasn't seen it. Do they react? -- **The removal test**: Remove the effect. Does the experience feel diminished? -- **The device test**: Run it on a phone, a tablet, a slow laptop. Still smooth? -- **The accessibility test**: Enable reduced motion. Is the fallback still beautiful? -- **The context test**: Does this effect make sense for THIS brand and audience? -- **The longevity test**: Will this still feel fresh in 6 months, or is it a trend? +- **The wow test**: Show it to someone who hasn't seen it. Do they react? +- **The removal test**: Take it away. Does the experience feel diminished, or does nobody notice? +- **The device test**: Run it on a phone, a tablet, a Chromebook. Still smooth? +- **The accessibility test**: Enable reduced motion. Still beautiful? +- **The context test**: Does this make sense for THIS brand and audience? -Remember: The goal isn't to use every API in the browser. It's to find the ONE technically ambitious idea that makes this specific interface unforgettable, then execute it with absolute precision. +Remember: "Technically extraordinary" isn't about using the newest API. It's about making an interface do something users didn't think a website could do. From 8bb0017752da263f07fc0800ad0b254db4292502 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 07:24:55 -0700 Subject: [PATCH 06/14] fix: overdrive demo works with hover slider, no AI slop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The demo must be purely visual (hover slider reveals after state, no clicking). New demo shows standard rectangular card vs organic blob-shaped composition — the visual difference is instant and communicates "beyond normal CSS" without animation or interaction. Co-Authored-By: Claude Opus 4.6 (1M context) --- public/js/demos/commands/overdrive.js | 56 +++++++++------------------ 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/public/js/demos/commands/overdrive.js b/public/js/demos/commands/overdrive.js index 315b397d8..04ced5a61 100644 --- a/public/js/demos/commands/overdrive.js +++ b/public/js/demos/commands/overdrive.js @@ -1,51 +1,33 @@ -// Overdrive command demo - shows a static list becoming a morphing shared-element transition +// Overdrive command demo - shows standard rectangular layout vs organic, non-standard composition export default { id: 'overdrive', - caption: 'Static list with page jump → Shared element morph transition', + caption: 'Standard rectangular layout → Organic, technically ambitious composition', before: ` -
-
PROJECTS
-
-
-
-
-
Redesign
-
3 tasks
-
-
-
-
-
-
Launch
-
7 tasks
-
-
+
+
+
Sarah Chen
+
Design Lead
+
+
142
Projects
+
38
Reviews
`, after: ` -
-
PROJECTS
-
-
-
R
-
-
Redesign
-
3 tasks
-
-
Active
-
-
-
L
-
-
Launch
-
7 tasks
-
+
+
+
+
+
SC
+
Sarah Chen
+
Design Lead
+
+
142
Projects
+
38
Reviews
-
view-transition-name on cards for shared element morphing
` }; From 577c9c872c314c89563dff6ef418e2893c7de929 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 11:13:05 -0700 Subject: [PATCH 07/14] Overdrive laser demo, deep link support, and split-compare fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Demo: - Laser-etched "Paul Bakaus" signature drawn in real-time on dark surface, adapted from pbakaus/shaders laser-precision - Two-canvas architecture: persistent burn canvas + cleared-per-frame spark overlay to prevent pixel accumulation - Smooth quadraticCurveTo rendering for fluid signature strokes - Sparks with motion trails, multi-layer tip glow Infrastructure: - Add init() support for command demos — JS can now execute after demo HTML is inserted into the DOM - Fix split-compare retriggerAnimations to not destroy canvas elements (clone-and-replace for CSS-only demos, individual retrigger when canvas is present) - Add deep linking to commands (#cmd-overdrive etc.) with hash tracking and initial load support - Remove auto-#hero hash — hero is the default state Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/audit/SKILL.md | 4 +- .claude/skills/critique/SKILL.md | 2 +- public/js/components/glass-terminal.js | 7 +- public/js/demo-renderer.js | 13 ++ public/js/demos/commands/overdrive.js | 307 +++++++++++++++++++++++-- public/js/effects/split-compare.js | 23 +- public/js/utils/scroll.js | 32 ++- 7 files changed, 355 insertions(+), 33 deletions(-) diff --git a/.claude/skills/audit/SKILL.md b/.claude/skills/audit/SKILL.md index e1ae379e2..e1711a94e 100644 --- a/.claude/skills/audit/SKILL.md +++ b/.claude/skills/audit/SKILL.md @@ -71,7 +71,7 @@ For each issue, document: - **Impact**: How it affects users - **WCAG/Standard**: Which standard it violates (if applicable) - **Recommendation**: How to fix it -- **Suggested command**: Which command to use (prefer: /animate, /quieter, /optimize, /adapt, /clarify, /distill, /delight, /onboard, /normalize, /audit, /harden, /polish, /extract, /bolder, /critique, /colorize — or other installed skills you're sure exist) +- **Suggested command**: Which command to use (prefer: /animate, /quieter, /optimize, /adapt, /clarify, /distill, /delight, /onboard, /normalize, /audit, /harden, /polish, /extract, /bolder, /arrange, /typeset, /critique, /colorize, /overdrive — or other installed skills you're sure exist) #### Critical Issues [Issues that block core functionality or violate WCAG A] @@ -108,7 +108,7 @@ Create actionable plan: ### Suggested Commands for Fixes -Map issues to available commands. Prefer these: /animate, /quieter, /optimize, /adapt, /clarify, /distill, /delight, /onboard, /normalize, /audit, /harden, /polish, /extract, /bolder, /critique, /colorize. You may also suggest other installed skills you're sure exist, but never invent commands. +Map issues to available commands. Prefer these: /animate, /quieter, /optimize, /adapt, /clarify, /distill, /delight, /onboard, /normalize, /audit, /harden, /polish, /extract, /bolder, /arrange, /typeset, /critique, /colorize, /overdrive. You may also suggest other installed skills you're sure exist, but never invent commands. Examples: - "Use `/normalize` to align with design system (addresses N theming issues)" diff --git a/.claude/skills/critique/SKILL.md b/.claude/skills/critique/SKILL.md index eb0d663b9..de81a8107 100644 --- a/.claude/skills/critique/SKILL.md +++ b/.claude/skills/critique/SKILL.md @@ -102,7 +102,7 @@ For each issue: - **What**: Name the problem clearly - **Why it matters**: How this hurts users or undermines goals - **Fix**: What to do about it (be concrete) -- **Command**: Which command to use (prefer: /animate, /quieter, /optimize, /adapt, /clarify, /distill, /delight, /onboard, /normalize, /audit, /harden, /polish, /extract, /bolder, /critique, /colorize — or other installed skills you're sure exist) +- **Command**: Which command to use (prefer: /animate, /quieter, /optimize, /adapt, /clarify, /distill, /delight, /onboard, /normalize, /audit, /harden, /polish, /extract, /bolder, /arrange, /typeset, /critique, /colorize, /overdrive — or other installed skills you're sure exist) ### Minor Observations Quick notes on smaller issues worth addressing. diff --git a/public/js/components/glass-terminal.js b/public/js/components/glass-terminal.js index 68b1c0d3d..6902c9c20 100644 --- a/public/js/components/glass-terminal.js +++ b/public/js/components/glass-terminal.js @@ -1,4 +1,4 @@ -import { renderCommandDemo } from "../demo-renderer.js"; +import { renderCommandDemo, initCommandDemo } from "../demo-renderer.js"; import { initSplitCompare } from "../effects/split-compare.js"; import { commandProcessSteps, commandCategories, commandRelationships } from "../data.js"; @@ -164,6 +164,7 @@ function setupDesktopScrollSpy(commands) { const cmd = commands.find(c => c.id === cmdId); if (cmd) { updateTerminal(cmd, terminalContent, commands); + history.replaceState(null, '', `#cmd-${cmdId}`); } } }); @@ -183,6 +184,7 @@ function setupDesktopScrollSpy(commands) { const cmd = commands.find(c => c.id === cmdId); if (cmd) { updateTerminal(cmd, terminalContent, commands); + history.replaceState(null, '', `#cmd-${cmdId}`); } e.scrollIntoView({ behavior: 'smooth', block: 'center' }); @@ -223,6 +225,7 @@ function updateTerminal(cmd, container, allCommands) { }); } + initCommandDemo(cmd.id, container); } // ============================================ @@ -293,6 +296,7 @@ function setupMobileInteractions(commands) { maxPosition: 90 }); } + if (commands[0]) initCommandDemo(commands[0].id, demoArea); // Pill click/tap handler pills.forEach(pill => { @@ -334,6 +338,7 @@ function setupMobileInteractions(commands) { }); } + initCommandDemo(cmdId, demoArea); }); }); } diff --git a/public/js/demo-renderer.js b/public/js/demo-renderer.js index 08ab6d786..7304e049e 100644 --- a/public/js/demo-renderer.js +++ b/public/js/demo-renderer.js @@ -5,6 +5,19 @@ import { getCommandDemo } from './demos/commands/index.js'; import { getSkillDemo } from './demos/skills/index.js'; +/** + * Initialize a command demo's JS after its HTML has been inserted into the DOM. + * Call this after innerHTML is set and split compare is initialized. + */ +export function initCommandDemo(commandId, container) { + const demo = getCommandDemo(commandId); + if (demo && typeof demo.init === 'function') { + const demoArea = container.querySelector('.split-after .split-content') || container; + console.log('[initCommandDemo]', commandId, 'demoArea:', demoArea); + demo.init(demoArea); + } +} + /** * Render a command demo with split-screen comparison */ diff --git a/public/js/demos/commands/overdrive.js b/public/js/demos/commands/overdrive.js index 04ced5a61..1cff8c91a 100644 --- a/public/js/demos/commands/overdrive.js +++ b/public/js/demos/commands/overdrive.js @@ -1,33 +1,296 @@ -// Overdrive command demo - shows standard rectangular layout vs organic, non-standard composition +// Overdrive command demo - laser-etched signature on a premium dark surface +// Laser effect adapted from pbakaus/shaders laser-precision + export default { id: 'overdrive', - caption: 'Standard rectangular layout → Organic, technically ambitious composition', + caption: 'Static flat card → Laser-etched signature effect', before: ` -
-
-
Sarah Chen
-
Design Lead
-
-
142
Projects
-
38
Reviews
+
+
+
It's time to spark your imagination. Welcome to the Impeccable Community.
+
Paul Bakaus
`, after: ` -
-
-
-
-
SC
-
Sarah Chen
-
Design Lead
-
-
142
Projects
-
38
Reviews
-
-
+ + +
+

It's time to spark your imagination.
Welcome to the Impeccable Community.

- ` + `, + + init(container) { + const burnCanvas = container.querySelector('.od-burn'); + const sparkCanvas = container.querySelector('.od-sparks'); + if (!burnCanvas || !sparkCanvas) return; + + const rect = burnCanvas.parentElement.getBoundingClientRect(); + const dpr = Math.min(window.devicePixelRatio || 1, 2); + + // Size both canvases + for (const c of [burnCanvas, sparkCanvas]) { + c.width = Math.round(rect.width * dpr); + c.height = Math.round(rect.height * dpr); + } + + const ctx = burnCanvas.getContext('2d'); // persistent burn trails + const sCtx = sparkCanvas.getContext('2d'); // cleared each frame + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + sCtx.setTransform(dpr, 0, 0, dpr, 0, 0); + const w = rect.width; + const h = rect.height; + + // Fill background + ctx.fillStyle = '#0e0d0b'; + ctx.fillRect(0, 0, w, h); + + // ── Signature path ── + function buildSignaturePath() { + const pts = []; + function bez(x0,y0, cx1,cy1, cx2,cy2, x1,y1, n) { + for (let i = 0; i <= n; i++) { + const t = i / n, mt = 1-t; + pts.push({ + x: mt*mt*mt*x0 + 3*mt*mt*t*cx1 + 3*mt*t*t*cx2 + t*t*t*x1, + y: mt*mt*mt*y0 + 3*mt*mt*t*cy1 + 3*mt*t*t*cy2 + t*t*t*y1 + }); + } + } + // P + bez(6,44, 5,32, 4,18, 8,8, 14); + bez(8,8, 16,5, 26,7, 26,16, 12); + bez(26,16, 26,22, 18,26, 14,28, 10); + // a + bez(14,28, 18,22, 23,20, 26,22, 8); + bez(26,22, 29,24, 28,30, 24,32, 6); + bez(24,32, 28,34, 30,30, 32,28, 5); + // u + bez(32,28, 34,36, 38,40, 42,32, 8); + bez(42,32, 44,26, 47,24, 48,28, 6); + // l + bez(48,28, 49,16, 50,6, 53,8, 10); + bez(53,8, 55,14, 56,28, 58,32, 8); + // B + bez(66,44, 66,32, 67,16, 70,8, 14); + bez(70,8, 78,4, 83,10, 79,18, 12); + bez(79,18, 84,15, 87,24, 80,30, 12); + bez(80,30, 78,34, 80,36, 84,32, 5); + // akaus + bez(84,32, 89,24, 94,22, 97,26, 8); + bez(97,26, 99,30, 96,34, 100,30, 5); + bez(100,30, 101,20, 102,14, 104,16, 8); + bez(104,16, 106,24, 109,28, 107,32, 6); + bez(107,32, 105,36, 110,36, 113,30, 6); + bez(113,30, 118,24, 122,22, 125,28, 8); + bez(125,28, 128,36, 133,38, 137,30, 8); + bez(137,30, 139,26, 142,24, 144,28, 5); + bez(144,28, 154,24, 170,22, 195,28, 16); + + // Same scaling as the static preview version + const rawW = 200; + const scale = (w * 0.7) / rawW; + const ox = (w - rawW * scale) / 2; + const oy = h * 0.52; + return pts.map(p => ({ x: p.x * scale + ox, y: p.y * scale * 0.75 + oy })); + } + + const sigPoints = buildSignaturePath(); + const segLengths = []; + let totalLength = 0; + for (let i = 1; i < sigPoints.length; i++) { + const dx = sigPoints[i].x - sigPoints[i-1].x; + const dy = sigPoints[i].y - sigPoints[i-1].y; + segLengths.push(Math.sqrt(dx*dx + dy*dy)); + totalLength += segLengths[segLengths.length - 1]; + } + + function posAt(dist) { + let d = 0; + for (let i = 0; i < segLengths.length; i++) { + if (d + segLengths[i] >= dist) { + const t = segLengths[i] > 0 ? (dist - d) / segLengths[i] : 0; + const p0 = sigPoints[i], p1 = sigPoints[i+1]; + return { x: p0.x + (p1.x - p0.x) * t, y: p0.y + (p1.y - p0.y) * t }; + } + d += segLengths[i]; + } + return sigPoints[sigPoints.length - 1]; + } + + // ── State ── + let drawnLength = 0; + const drawSpeed = totalLength / 3.0; + let prevTip = sigPoints[0]; + let sparks = []; + let phase = 'drawing'; + let phaseTimer = 0; + let lastTime = 0; + + // Track all drawn points for smooth rendering + const drawnPts = []; + + function drawBurnTrail() { + if (drawnPts.length < 2) return; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + + // Draw smooth path through all points using quadratic curves + function strokeSmooth(color, width) { + ctx.beginPath(); + ctx.moveTo(drawnPts[0].x, drawnPts[0].y); + for (let i = 1; i < drawnPts.length - 1; i++) { + const mx = (drawnPts[i].x + drawnPts[i+1].x) / 2; + const my = (drawnPts[i].y + drawnPts[i+1].y) / 2; + ctx.quadraticCurveTo(drawnPts[i].x, drawnPts[i].y, mx, my); + } + const last = drawnPts[drawnPts.length - 1]; + ctx.lineTo(last.x, last.y); + ctx.strokeStyle = color; + ctx.lineWidth = width; + ctx.stroke(); + } + + strokeSmooth('rgba(180, 100, 30, 0.12)', 5); + strokeSmooth('rgba(220, 140, 50, 0.3)', 2.5); + strokeSmooth('rgba(255, 210, 130, 0.7)', 1.2); + strokeSmooth('rgba(255, 248, 235, 0.6)', 0.4); + } + + function emitSparks(x, y, count) { + for (let i = 0; i < count; i++) { + const angle = Math.random() * Math.PI * 2; + const speed = 50 + Math.random() * 140; + sparks.push({ + x, y, vx: Math.cos(angle) * speed, vy: Math.sin(angle) * speed, + life: 0.15 + Math.random() * 0.35, maxLife: 0.15 + Math.random() * 0.35, + size: 0.3 + Math.random() * 1.0, bright: Math.random() > 0.4 + }); + } + } + + function draw(timestamp) { + if (!document.contains(burnCanvas)) return; + + // Actual frame delta time + if (!lastTime) lastTime = timestamp; + const dt = Math.min(0.05, (timestamp - lastTime) / 1000); + lastTime = timestamp; + + switch (phase) { + case 'drawing': + drawnLength += drawSpeed * dt; + if (drawnLength >= totalLength) { + drawnLength = totalLength; + phase = 'holding'; + phaseTimer = 0; + emitSparks(prevTip.x, prevTip.y, 8); + } + const tip = posAt(drawnLength); + drawnPts.push({ x: tip.x, y: tip.y }); + prevTip = tip; + if (Math.random() < 0.4) emitSparks(tip.x, tip.y, 1); + // Redraw full smooth trail (clear burn canvas first) + ctx.fillStyle = '#0e0d0b'; + ctx.fillRect(0, 0, w, h); + drawBurnTrail(); + break; + + case 'holding': + phaseTimer += dt; + if (phaseTimer >= 3.5) { phase = 'fading'; phaseTimer = 0; } + break; + + case 'fading': + phaseTimer += dt; + ctx.fillStyle = 'rgba(14, 13, 11, 0.04)'; + ctx.fillRect(0, 0, w, h); + if (phaseTimer >= 2.0) { + ctx.fillStyle = '#0e0d0b'; + ctx.fillRect(0, 0, w, h); + drawnLength = 0; prevTip = sigPoints[0]; + sparks = []; drawnPts.length = 0; + phase = 'drawing'; phaseTimer = 0; + } + break; + } + + // Update sparks + for (let i = sparks.length - 1; i >= 0; i--) { + const s = sparks[i]; + s.x += s.vx * dt; s.y += s.vy * dt; + s.vx *= 0.94; s.vy *= 0.94; s.vy += 100 * dt; + s.life -= dt; + if (s.life <= 0) sparks.splice(i, 1); + } + + // Draw sparks + tip on overlay (cleared each frame) + sCtx.clearRect(0, 0, w, h); + + for (const s of sparks) { + const t = s.life / s.maxLife; + const r = s.size * (0.3 + t * 0.7); + // Spark trail + const speed = Math.sqrt(s.vx*s.vx + s.vy*s.vy); + if (speed > 20) { + const tl = speed * 0.01; + sCtx.beginPath(); + sCtx.moveTo(s.x, s.y); + sCtx.lineTo(s.x - s.vx/speed * tl, s.y - s.vy/speed * tl); + sCtx.strokeStyle = s.bright + ? `rgba(255,255,240,${(t*0.4).toFixed(3)})` + : `rgba(255,180,60,${(t*0.3).toFixed(3)})`; + sCtx.lineWidth = r * 0.5; + sCtx.lineCap = 'round'; + sCtx.stroke(); + } + sCtx.beginPath(); + sCtx.arc(s.x, s.y, r, 0, Math.PI * 2); + sCtx.fillStyle = s.bright + ? `rgba(255,255,255,${(t*0.85).toFixed(3)})` + : `rgba(255,200,80,${(t*0.75).toFixed(3)})`; + sCtx.fill(); + } + + // Draw laser tip on overlay + if (phase === 'drawing' && drawnLength < totalLength) { + const tip = posAt(drawnLength); + const fl = 0.85 + Math.random() * 0.15; + + // Wide heat bloom + const g0 = sCtx.createRadialGradient(tip.x, tip.y, 0, tip.x, tip.y, 35); + g0.addColorStop(0, `rgba(255,100,20,${0.15*fl})`); + g0.addColorStop(0.4, `rgba(200,60,10,${0.05*fl})`); + g0.addColorStop(1, 'rgba(150,40,10,0)'); + sCtx.fillStyle = g0; sCtx.beginPath(); sCtx.arc(tip.x, tip.y, 35, 0, Math.PI*2); sCtx.fill(); + + // Amber corona + const g1 = sCtx.createRadialGradient(tip.x, tip.y, 0, tip.x, tip.y, 16); + g1.addColorStop(0, `rgba(255,180,60,${0.45*fl})`); + g1.addColorStop(0.5, `rgba(255,140,40,${0.15*fl})`); + g1.addColorStop(1, 'rgba(200,80,20,0)'); + sCtx.fillStyle = g1; sCtx.beginPath(); sCtx.arc(tip.x, tip.y, 16, 0, Math.PI*2); sCtx.fill(); + + // White-hot core + const g2 = sCtx.createRadialGradient(tip.x, tip.y, 0, tip.x, tip.y, 6); + g2.addColorStop(0, `rgba(255,255,255,${0.95*fl})`); + g2.addColorStop(0.3, `rgba(255,250,240,${0.7*fl})`); + g2.addColorStop(0.6, `rgba(255,220,160,${0.3*fl})`); + g2.addColorStop(1, 'rgba(255,180,80,0)'); + sCtx.fillStyle = g2; sCtx.beginPath(); sCtx.arc(tip.x, tip.y, 6, 0, Math.PI*2); sCtx.fill(); + + // Overexposed center + const g3 = sCtx.createRadialGradient(tip.x, tip.y, 0, tip.x, tip.y, 2.5); + g3.addColorStop(0, `rgba(255,255,255,${fl})`); + g3.addColorStop(1, 'rgba(255,255,255,0)'); + sCtx.fillStyle = g3; sCtx.beginPath(); sCtx.arc(tip.x, tip.y, 2.5, 0, Math.PI*2); sCtx.fill(); + } + + requestAnimationFrame(draw); + } + + requestAnimationFrame(draw); + } }; diff --git a/public/js/effects/split-compare.js b/public/js/effects/split-compare.js index b1e81d26a..d54071651 100644 --- a/public/js/effects/split-compare.js +++ b/public/js/effects/split-compare.js @@ -48,10 +48,27 @@ export function initSplitCompare(container, options = {}) { } function retriggerAnimations() { - // Find all elements with animations in the "after" content and re-trigger them + // Re-trigger CSS animations in the "after" content. + // If there's a canvas (e.g. overdrive shader), we can't clone-and-replace + // because that destroys JS-driven animations. In that case, retrigger + // individual elements. Otherwise, use the fast clone approach. const afterContent = splitAfter.querySelector('.split-content'); - if (afterContent) { - // Clone and replace to restart all CSS animations + if (!afterContent) return; + + const hasCanvas = afterContent.querySelector('canvas, .od-burn, .od-sparks'); + if (hasCanvas) { + // Safe path: retrigger CSS animations individually, skip canvas + afterContent.querySelectorAll('*').forEach(el => { + if (el.tagName === 'CANVAS') return; + const anim = getComputedStyle(el).animationName; + if (anim && anim !== 'none') { + el.style.animation = 'none'; + el.offsetHeight; + el.style.animation = ''; + } + }); + } else { + // Fast path: clone and replace to restart all CSS animations const clone = afterContent.cloneNode(true); afterContent.parentNode.replaceChild(clone, afterContent); } diff --git a/public/js/utils/scroll.js b/public/js/utils/scroll.js index 4f31c06bd..ebe48b5a3 100644 --- a/public/js/utils/scroll.js +++ b/public/js/utils/scroll.js @@ -22,6 +22,21 @@ export function initHashTracking() { let ticking = false; function updateHash() { + // Don't override command deep links while user is in the commands section + if (currentHash.startsWith('cmd-')) { + const cmdEl = document.getElementById(currentHash); + if (cmdEl) { + const rect = cmdEl.getBoundingClientRect(); + // Only clear the cmd hash if user scrolled well away from commands section + if (rect.top > window.innerHeight * 2 || rect.bottom < -window.innerHeight) { + currentHash = ''; + } else { + ticking = false; + return; + } + } + } + const scrollY = window.scrollY; const viewportHeight = window.innerHeight; const triggerPoint = scrollY + viewportHeight * 0.3; @@ -38,6 +53,9 @@ export function initHashTracking() { } }); + // Don't set #hero — it's the default state, no hash needed + if (activeSection === 'hero') activeSection = ''; + if (activeSection !== currentHash) { currentHash = activeSection; if (activeSection) { @@ -59,17 +77,23 @@ export function initHashTracking() { // Handle initial hash on page load - instant jump if (window.location.hash) { - const target = document.querySelector(window.location.hash); + const hash = window.location.hash.slice(1); + const target = document.getElementById(hash); if (target) { + currentHash = hash; setTimeout(() => { const offset = 40; const targetPosition = target.getBoundingClientRect().top + window.scrollY - offset; window.scrollTo({ top: targetPosition, behavior: 'auto' }); + + // If it's a command deep link, activate it + if (hash.startsWith('cmd-') && target.classList.contains('manual-entry')) { + target.click(); + } }, 100); } + } else { + // No hash — don't set one on initial load } - - // Initial check - updateHash(); } From 8427deac3ea46bda24f186b939dc46f50799280a Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 11:25:54 -0700 Subject: [PATCH 08/14] Improve typeset and arrange demos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Typeset: make the before worse (all text same size/color = no hierarchy) and the after more dramatic (bigger heading, more size contrast). The transformation should be instantly visible on hover. Arrange: fix heading split (eyebrow+heading was a typeset change, not arrange) — keep it as a single heading to stay on-brand. Co-Authored-By: Claude Opus 4.6 (1M context) --- public/js/demos/commands/arrange.js | 5 +---- public/js/demos/commands/typeset.js | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/public/js/demos/commands/arrange.js b/public/js/demos/commands/arrange.js index e9299c6a8..ae1020c70 100644 --- a/public/js/demos/commands/arrange.js +++ b/public/js/demos/commands/arrange.js @@ -25,10 +25,7 @@ export default { after: `
-
-
Team
-
Members
-
+
Team Members
AC
diff --git a/public/js/demos/commands/typeset.js b/public/js/demos/commands/typeset.js index 2f226e054..0eb479260 100644 --- a/public/js/demos/commands/typeset.js +++ b/public/js/demos/commands/typeset.js @@ -1,23 +1,23 @@ -// Typeset command demo - shows generic typography becoming intentional and hierarchical +// Typeset command demo - shows flat, hierarchyless text becoming intentional typography export default { id: 'typeset', - caption: 'Generic system fonts → Intentional type hierarchy', + caption: 'No type hierarchy → Clear, intentional typography', before: `
-
Project Update
-
Q1 Design Sprint
-

The team completed the redesign of the dashboard. All components have been reviewed and approved by stakeholders.

-
Updated 2 hours ago
+
Project Update
+
Q1 Design Sprint
+
The team completed the redesign of the dashboard. All components have been reviewed and approved by stakeholders.
+
Updated 2 hours ago
`, after: `
-
Project Update
-
Q1 Design Sprint
-

The team completed the redesign of the dashboard. All components reviewed and approved.

-
Updated 2 hours ago
+
Project Update
+
Q1 Design Sprint
+

The team completed the redesign of the dashboard. All components reviewed and approved.

+
Updated 2 hours ago
` }; From 5b5bba64888b56ac79790ce691eb713f64cac8f1 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 11:29:07 -0700 Subject: [PATCH 09/14] Add .wrangler/ to gitignore Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 452537e61..a5246fa5c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ Thumbs.db # Environment .env .env.local + +# Cloudflare +.wrangler/ From 9bdb836903834a8cba377e83eb1624ee445d4461 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 11:42:59 -0700 Subject: [PATCH 10/14] Mark overdrive as beta, remove product-level suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Skill changes: - Remove real-time collaboration section (product decision, not UI) - Remove service workers / offline-first (product decision) - Remove SharedArrayBuffer (too niche) - Replace "application architecture" section with "performance-critical UI" — focused on making existing features feel fast - Add explicit note: this skill enhances how UI FEELS, not what a product DOES Beta label: - Add betaCommands list to data.js - Show BETA badge on /overdrive in command palette - Show β symbol on periodic table element - Show BETA badge on cheatsheet page Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/overdrive/SKILL.md | 15 +- public/cheatsheet.html | 3 +- public/css/styles.css | 2 +- public/css/workflow.css | 14 ++ public/js/components/framework-viz.js | 20 ++- public/js/components/glass-terminal.js | 6 +- public/js/data.js | 5 + public/js/demos/commands/overdrive.js | 220 +++++++++++++++---------- source/skills/overdrive/SKILL.md | 15 +- 9 files changed, 190 insertions(+), 110 deletions(-) diff --git a/.claude/skills/overdrive/SKILL.md b/.claude/skills/overdrive/SKILL.md index d90660d63..ef701878f 100644 --- a/.claude/skills/overdrive/SKILL.md +++ b/.claude/skills/overdrive/SKILL.md @@ -1,6 +1,6 @@ --- name: overdrive -description: Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or real-time collaboration — make users ask "how did they do that?" +description: Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or scroll-driven reveals — make users ask "how did they do that?" user-invokable: true args: - name: target @@ -28,8 +28,8 @@ Pages, hero sections, landing pages, portfolios — the "wow" is often sensory: ### For functional UI Tables, forms, dialogs, navigation — the "wow" is in how it FEELS: a dialog that morphs from the button that triggered it via View Transitions, a data table that renders 100k rows at 60fps via virtual scrolling, a form with streaming validation that feels instant, drag-and-drop with spring physics. -### For application architecture -The "wow" is invisible but felt: offline-first with service workers (the app works on a plane), real-time collaboration (cursors appearing as someone else types), near-native computation via WASM, background processing via Web Workers that never blocks the UI. +### For performance-critical UI +The "wow" is invisible but felt: a search that filters 50k items without a flicker, a complex form that never blocks the main thread, an image editor that processes in near-real-time. The interface just never hesitates. ### For data-heavy interfaces Charts and dashboards — the "wow" is in fluidity: GPU-accelerated rendering via Canvas/WebGL for massive datasets, animated transitions between data states, force-directed graph layouts that settle naturally. @@ -66,17 +66,14 @@ Organized by what you're trying to achieve, not by technology name. ### Push performance boundaries - **Web Workers** — move computation off the main thread. Heavy data processing, image manipulation, search indexing — anything that would cause jank. - **OffscreenCanvas** — render in a Worker thread. The main thread stays free while complex visuals render in the background. -- **WASM** — near-native performance for computation-heavy features. Image processing, encryption, physics simulations, codecs. -- **Service Workers** — offline-first experiences, background sync, push notifications. The app works without a network. - -### Enable real-time collaboration -- **WebSockets / SSE** — live cursors, collaborative editing, streaming updates. The interface feels alive. -- **SharedArrayBuffer** — shared memory between threads for high-performance real-time data. +- **WASM** — near-native performance for computation-heavy features. Image processing, physics simulations, codecs. ### Interact with the device - **Web Audio API** — spatial audio, audio-reactive visualizations, sonic feedback. Requires user gesture to start. - **Device APIs** — orientation, ambient light, geolocation. Use sparingly and always with user permission. +**NOTE**: This skill is about enhancing how an interface FEELS, not changing what a product DOES. Adding real-time collaboration, offline support, or new backend capabilities are product decisions, not UI enhancements. Focus on making existing features feel extraordinary. + ## Implement with Discipline ### Progressive enhancement is non-negotiable diff --git a/public/cheatsheet.html b/public/cheatsheet.html index 0f0d4d7b6..d0df0ea92 100644 --- a/public/cheatsheet.html +++ b/public/cheatsheet.html @@ -267,8 +267,9 @@ } } + const isBeta = cmd.id === 'overdrive'; html += `
-
/${cmd.id}
+
/${cmd.id}${isBeta ? ' BETA' : ''}
${cmd.description}
${metaHtml ? `
${metaHtml}
` : ''} diff --git a/public/css/styles.css b/public/css/styles.css index 357364198..148c95379 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */ -.split-container:before{content:"";background-image:linear-gradient(var(--color-mist) 1px, transparent 1px), linear-gradient(90deg, var(--color-mist) 1px, transparent 1px);opacity:.3;pointer-events:none;background-size:20px 20px;position:absolute;inset:0}.split-container:after{content:"← Drag →";letter-spacing:.1em;text-transform:uppercase;color:var(--color-ash);background:var(--color-paper);opacity:.8;z-index:10;border-radius:4px;padding:4px 12px;font-size:.625rem;font-weight:600;transition:opacity .3s;position:absolute;bottom:12px;left:50%;transform:translate(-50%)}.split-container:hover:after{opacity:0}.split-after .impeccable-card{box-shadow:0 10px 40px #00000014}@keyframes splitEntry{0%{opacity:0;transform:translate(-50%)skew(-10deg)scaleY(.8)}to{opacity:1;transform:translate(-50%)skew(-10deg)scaleY(1)}}.split-divider{animation:splitEntry .6s var(--ease-out) .3s backwards}.split-label-item{transition:color var(--duration-fast) var(--ease-out);cursor:default}.split-label-item:hover{color:var(--color-text)}.split-label-item[data-point=after]:hover .split-label-dot--accent{transform:scale(1.3)}.split-label-dot{transition:transform var(--duration-fast) var(--ease-spring)}.split-badge{letter-spacing:.08em;text-transform:uppercase;z-index:5;pointer-events:none;border-radius:3px;padding:3px 8px;font-size:.625rem;font-weight:600;position:absolute;top:10px}.split-badge--before{color:var(--color-ash);background:var(--color-paper);border:1px solid var(--color-mist);left:10px}.split-badge--after{color:var(--color-paper);background:var(--color-accent);right:10px}@media (hover:none){.split-container:after{content:"← Swipe →"}}@media (max-width:600px){.split-label{padding:4px 10px;font-size:.5625rem}}.commands-section{padding:var(--spacing-xl) 0;background:var(--color-paper);position:relative}.commands-gallery{display:block}.commands-container{gap:var(--spacing-2xl);grid-template-columns:1fr 1.2fr;align-items:start;display:grid}@media (max-width:900px){.commands-container{grid-template-columns:1fr}}.command-manual{gap:var(--spacing-sm);flex-direction:column;padding-bottom:20vh;display:flex}.command-category-header{font-family:var(--font-display);color:var(--color-accent);text-transform:uppercase;letter-spacing:.1em;padding:var(--spacing-lg) var(--spacing-lg) var(--spacing-sm);margin-top:var(--spacing-md);border-bottom:1px solid var(--color-mist);font-size:.875rem;font-weight:600}.command-category-header:first-child{margin-top:0}.manual-entry{padding:var(--spacing-lg);padding-left:calc(var(--spacing-lg) + 16px);border-left:2px solid var(--color-mist);transition:border-color .4s var(--ease-out), opacity .4s var(--ease-out), background .4s var(--ease-out), transform .4s var(--ease-out);opacity:.4;cursor:pointer;position:relative;transform:translate(-16px)}.manual-entry:hover{opacity:.7}.manual-entry.active{border-left-color:var(--color-accent);opacity:1;background:linear-gradient(to right, var(--color-bg), transparent);transform:translate(0)}.manual-cmd-name{font-family:var(--font-mono);margin:0 0 var(--spacing-sm);color:var(--color-ink);font-size:1.5rem;font-weight:500}.manual-cmd-desc{color:var(--color-charcoal);margin:0;font-size:1rem;line-height:1.6}.manual-cmd-rel{color:var(--color-ash);margin-top:var(--spacing-sm);flex-wrap:wrap;align-items:center;gap:.5ch;font-size:.8125rem;display:flex}.manual-cmd-rel .rel-icon{color:var(--color-accent);font-weight:600}.manual-cmd-rel code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 6px;font-size:.75rem}.glass-terminal-wrapper{top:var(--spacing-xl);height:calc(100vh - var(--spacing-xl) * 2);min-height:500px;max-height:800px;position:sticky}.terminal-stack{perspective:1200px;height:100%;position:relative}.terminal-stack-tabs{z-index:10;gap:4px;display:flex;position:absolute;top:-31px;right:8px}.terminal-stack-tab{font-family:var(--font-mono);background:var(--color-cream);border:1px solid var(--color-mist);color:var(--color-ash);cursor:pointer;border-bottom:none;border-radius:6px 6px 0 0;padding:5px 12px;font-size:.75rem;transition:all .2s}.terminal-stack-tab:hover{background:var(--color-paper);color:var(--color-charcoal)}.terminal-stack-tab.active{background:var(--color-paper);color:var(--color-ink);border-color:var(--color-mist)}.terminal-window{transform-origin:bottom;transition:transform .4s cubic-bezier(.4,0,.2,1),opacity .3s,filter .3s;position:absolute;inset:0}.terminal-window--demo{z-index:2}.terminal-window--demo.is-back{opacity:.6;filter:brightness(.92);pointer-events:none;z-index:1;transform:translateY(16px)translate(12px)scale(.96)}.terminal-window--source{z-index:1;opacity:.6;filter:brightness(.92);pointer-events:none;transform:translateY(16px)translate(12px)scale(.96)}.terminal-window--source.is-front{opacity:1;filter:brightness();pointer-events:auto;z-index:2;transform:translateY(0)translate(0)scale(1)}.source-window{background:var(--color-paper);-webkit-backdrop-filter:blur(12px);border:1px solid var(--color-mist);border-radius:8px;flex-direction:column;height:100%;display:flex;overflow:hidden;box-shadow:0 20px 60px -10px #00000026}.source-header{background:var(--color-cream);border-bottom:1px solid var(--color-mist);flex-shrink:0;align-items:center;gap:8px;padding:12px 16px;display:flex}.source-title{font-family:var(--font-mono);color:var(--color-ink);font-size:.875rem;font-weight:500}.source-body{padding:var(--spacing-md);font-family:var(--font-mono);color:var(--color-charcoal);overscroll-behavior:contain;white-space:pre-wrap;word-break:break-word;background:var(--color-cream);flex:1;font-size:.75rem;line-height:1.5;overflow-y:auto}.source-loading{color:var(--color-ash);font-style:italic}@media (max-width:900px){.glass-terminal-wrapper{display:none}}.glass-terminal{background:var(--color-paper);-webkit-backdrop-filter:blur(12px);border:1px solid var(--color-mist);border-radius:8px;flex-direction:column;height:100%;display:flex;overflow:hidden;box-shadow:0 20px 60px -10px #00000026}.terminal-header{background:var(--color-cream);border-bottom:1px solid var(--color-mist);align-items:center;gap:8px;padding:12px 16px;display:flex}.terminal-dot{border-radius:50%;width:10px;height:10px}.terminal-dot.red{background:#ff5f56}.terminal-dot.yellow{background:#ffbd2e}.terminal-dot.green{background:#27c93f}.terminal-title{font-family:var(--font-mono);color:var(--color-ash);margin-left:auto;font-size:.75rem}.terminal-body{padding:var(--spacing-md);font-family:var(--font-mono);color:var(--color-ink);flex-direction:column;flex:1;min-height:0;font-size:.9375rem;display:flex;overflow-y:auto}.terminal-line{margin-bottom:var(--spacing-sm);gap:var(--spacing-sm);line-height:1.5;display:flex}.terminal-prompt{color:var(--color-accent);-webkit-user-select:none;user-select:none;font-weight:700}.terminal-cursor{background:var(--color-accent);vertical-align:middle;width:8px;height:1.2em;animation:1s step-end infinite blink;display:inline-block}.terminal-output{color:var(--color-ash);margin-bottom:var(--spacing-md);white-space:pre-wrap}@media (max-height:800px){.terminal-output{display:none}}.terminal-cmd{color:var(--color-accent);font-weight:600}.terminal-step{color:var(--color-charcoal)}.terminal-done{color:var(--color-success,#22c55e);font-weight:500}.terminal-preview{background:var(--color-paper);margin:var(--spacing-sm) 0;border-radius:12px;flex:1;min-height:0;overflow:hidden}.terminal-cursor-line{flex-shrink:0;margin-top:var(--spacing-sm)!important}.terminal-preview .demo-split-comparison{flex-direction:column;height:100%;display:flex}.terminal-preview .demo-split-comparison .split-container{cursor:ew-resize;-webkit-user-select:none;user-select:none;background:var(--color-cream);flex:1;min-height:0;position:relative;overflow:hidden}.terminal-preview .demo-split-comparison .split-before,.terminal-preview .demo-split-comparison .split-after{padding:var(--spacing-md);justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.terminal-preview .demo-split-comparison .split-before{z-index:1;background:var(--color-cream)}.terminal-preview .demo-split-comparison .split-after{z-index:2;background:var(--color-paper);clip-path:polygon(58% 0%,100% 0%,100% 100%,42% 100%)}.terminal-preview .demo-split-comparison .split-content{flex-direction:column;justify-content:center;align-items:center;width:100%;max-width:280px;display:flex}.terminal-preview .demo-split-comparison .split-divider{background:var(--color-accent);pointer-events:none;z-index:3;width:2px;position:absolute;top:0;bottom:0;left:50%;transform:translate(-50%)skew(-10deg);box-shadow:0 0 12px #0000001a}.terminal-preview .demo-split-comparison .split-label{letter-spacing:.08em;text-transform:uppercase;color:var(--color-paper);background:var(--color-accent);white-space:nowrap;border-radius:3px;padding:4px 10px;font-size:.5625rem;font-weight:600;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)skew(10deg)}.terminal-preview .demo-split-comparison .demo-caption{color:var(--color-ash);text-align:center;padding:var(--spacing-sm) var(--spacing-md);flex-shrink:0;font-size:.75rem}@keyframes blink{50%{opacity:0}}.casestudies-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist);position:relative}.transformations-tabbed{margin-top:var(--spacing-xl)}.transformation-tabs{gap:var(--spacing-xs);border-bottom:1px solid var(--color-mist);margin-bottom:var(--spacing-lg);display:flex}.transformation-tab{font-family:var(--font-display);color:var(--color-ash);padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;background:0 0;border:none;font-size:.9375rem;font-weight:500;transition:color .2s;position:relative}.transformation-tab:hover{color:var(--color-charcoal)}.transformation-tab.active{color:var(--color-ink)}.transformation-tab.active:after{content:"";background:var(--color-accent);height:2px;position:absolute;bottom:-1px;left:0;right:0}.transformation-panels{position:relative}.transformation-panel{gap:var(--spacing-lg);flex-direction:column;animation:.3s fadeInPanel;display:none}.transformation-panel.active{display:flex}@keyframes fadeInPanel{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.transformation-images{align-items:center;gap:var(--spacing-md);display:flex}.transformation-before,.transformation-after{flex:1;margin:0}.transformation-before img,.transformation-after img,.transformation-placeholder{aspect-ratio:16/10;object-fit:cover;border:1px solid var(--color-mist);cursor:pointer;border-radius:8px;width:100%;transition:transform .2s,box-shadow .2s}.transformation-before img:hover,.transformation-after img:hover,.transformation-placeholder:hover{transform:scale(1.02);box-shadow:0 8px 24px -4px #00000026}.transformation-placeholder{background:linear-gradient(135deg, var(--color-mist) 0%, var(--color-cream) 100%);color:var(--color-ash);justify-content:center;align-items:center;font-size:.8125rem;font-style:italic;display:flex}.transformation-before figcaption,.transformation-after figcaption{text-transform:uppercase;letter-spacing:.05em;color:var(--color-ash);margin-top:var(--spacing-xs);text-align:center;font-size:.75rem;font-weight:600}.transformation-arrow{color:var(--color-accent);flex-shrink:0;font-size:1.5rem;font-weight:300}.transformation-info{max-width:600px}.transformation-title{font-family:var(--font-display);color:var(--color-ink);margin:0 0 var(--spacing-xs);font-size:1.25rem;font-weight:600}.transformation-desc{color:var(--color-charcoal);margin:0 0 var(--spacing-sm);font-size:.9375rem;line-height:1.6}.transformation-commands{flex-wrap:wrap;gap:6px;display:flex}.transformation-command{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-charcoal);border-radius:4px;padding:4px 10px;font-size:.75rem}.lightbox{z-index:1000;opacity:0;visibility:hidden;background:#000000e6;justify-content:center;align-items:center;transition:opacity .3s,visibility .3s;display:flex;position:fixed;inset:0}.lightbox.active{opacity:1;visibility:visible}.lightbox-close{color:#fff;cursor:pointer;opacity:.7;background:0 0;border:none;font-size:2.5rem;line-height:1;transition:opacity .2s;position:absolute;top:20px;right:24px}.lightbox-close:hover{opacity:1}.lightbox-image{object-fit:contain;border-radius:8px;max-width:90vw;max-height:85vh;box-shadow:0 20px 60px #00000080}@media (max-width:768px){.transformation-images{flex-direction:column}.transformation-arrow{transform:rotate(90deg)}.transformation-before,.transformation-after{width:100%}}.hero-version-link{color:var(--color-ash);margin-top:var(--spacing-sm);font-size:.8125rem}.hero-version-link a{color:var(--color-ash);border-bottom:1px solid #0000;text-decoration:none;transition:color .2s,border-color .2s}.hero-version-link a:hover{color:var(--color-accent);border-bottom-color:var(--color-accent)}.changelog-section{padding:var(--spacing-xl) 0;border-top:1px solid var(--color-mist);position:relative}.changelog-list{flex-direction:column;gap:0;display:flex}.changelog-entry{padding:var(--spacing-md) 0;border-bottom:1px solid var(--color-mist)}.changelog-entry:first-child{border-top:1px solid var(--color-mist)}.changelog-version-header{align-items:baseline;gap:var(--spacing-sm);margin-bottom:var(--spacing-sm);display:flex}.changelog-version{font-family:var(--font-mono);color:var(--color-ink);font-size:1.125rem;font-weight:600}.changelog-date{color:var(--color-ash);font-size:.8125rem}.changelog-items{padding-left:var(--spacing-md);color:var(--color-charcoal);margin:0;line-height:1.7}.changelog-items li{margin-bottom:var(--spacing-xs)}.changelog-items code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 6px;font-size:.875em}.faq-section{padding:var(--spacing-xl) 0;border-top:1px solid var(--color-mist);position:relative}.faq-list{flex-direction:column;gap:0;display:flex}.faq-item{border-bottom:1px solid var(--color-mist)}.faq-item:first-child{border-top:1px solid var(--color-mist)}.faq-question{font-family:var(--font-display);color:var(--color-ink);padding:var(--spacing-md) 0;cursor:pointer;justify-content:space-between;align-items:center;font-size:1.125rem;font-weight:500;list-style:none;transition:color .2s;display:flex}.faq-question::-webkit-details-marker{display:none}.faq-question:after{content:"+";font-family:var(--font-body);color:var(--color-accent);transition:transform .3s var(--ease-out);font-size:1.5rem;font-weight:300}.faq-item[open] .faq-question:after{transform:rotate(45deg)}.faq-question:hover{color:var(--color-accent)}.faq-answer{padding:0 0 var(--spacing-md);color:var(--color-charcoal);animation:faqFadeIn .3s var(--ease-out);line-height:1.7}.faq-answer p{margin:0 0 var(--spacing-sm)}.faq-answer p:last-child{margin-bottom:0}.faq-answer ul{margin:var(--spacing-sm) 0;padding-left:var(--spacing-md)}.faq-answer li{margin-bottom:var(--spacing-xs)}.faq-answer code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 6px;font-size:.875em}.faq-answer a{color:var(--color-accent);border-bottom:1px solid #0000;text-decoration:none;transition:border-color .2s}.faq-answer a:hover{border-bottom-color:var(--color-accent)}@keyframes faqFadeIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.skills-section{padding:var(--spacing-xl) 0;background:var(--color-bg);position:relative;overflow:hidden}.skills-gallery{display:block;position:relative}.gallery-track{gap:var(--spacing-lg);scroll-snap-type:x mandatory;padding:var(--spacing-md) var(--spacing-lg) var(--spacing-xl);-webkit-overflow-scrolling:touch;scrollbar-width:none;cursor:grab;display:flex;overflow-x:auto}.gallery-track:active{cursor:grabbing}.gallery-track::-webkit-scrollbar{display:none}.gallery-frame{scroll-snap-align:center;background:var(--color-paper);border:1px solid var(--color-mist);opacity:.4;max-width:1100px;transition:opacity .6s var(--ease-out), transform .6s var(--ease-out), box-shadow .6s var(--ease-out);border-radius:2px;flex:0 0 80vw;position:relative;overflow:hidden;transform:scale(.95);box-shadow:0 4px 6px -1px #0000000d,0 20px 50px -10px #0000001a}.gallery-frame.active{opacity:1;border-color:var(--color-charcoal);border-width:1px;transform:scale(1);box-shadow:0 20px 25px -5px #0000001a,0 40px 100px -20px #0003}.gallery-content{grid-template-columns:1.2fr 1fr;height:600px;display:grid}@media (max-width:900px){.gallery-frame{flex:0 0 90vw}.gallery-content{grid-template-columns:1fr;height:auto;min-height:600px}}.gallery-visual{background:var(--color-cream);border-right:1px solid var(--color-mist);padding:var(--spacing-lg);justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden}.gallery-info{padding:var(--spacing-xl);flex-direction:column;display:flex;overflow-y:auto}.gallery-header{margin-bottom:var(--spacing-lg)}.gallery-title{font-family:var(--font-display);margin:0 0 var(--spacing-xs);color:var(--color-ink);font-size:2.5rem;font-style:italic}.gallery-meta{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.75rem}.gallery-desc{color:var(--color-charcoal);margin-bottom:var(--spacing-xl);max-width:45ch;font-size:1.125rem;line-height:1.6}.gallery-tags{gap:var(--spacing-xs);flex-wrap:wrap;margin-top:auto;display:flex}.gallery-tag{border:1px solid var(--color-mist);color:var(--color-ash);border-radius:4px;padding:6px 12px;font-size:.8125rem}.gallery-map{margin-top:var(--spacing-lg);justify-content:center;gap:8px;display:flex}.gallery-dot{background:var(--color-mist);cursor:pointer;width:40px;height:2px;font:inherit;border:none;padding:0;transition:all .3s;position:relative}.gallery-dot:after{content:"";position:absolute;inset:-10px 0}.gallery-dot:focus-visible{outline:2px solid var(--color-accent);outline-offset:4px;border-radius:1px}.gallery-dot.active{background:var(--color-accent);height:4px}.demo-tabbed-container{flex-direction:column;display:flex}.demo-tabs{background:var(--color-paper);border-bottom:1px solid var(--color-mist);justify-content:center;gap:0;margin-bottom:0;display:flex}.demo-tab{padding:var(--spacing-sm) var(--spacing-lg);font-family:var(--font-mono);letter-spacing:.05em;text-transform:uppercase;color:var(--color-ash);cursor:pointer;transition:all var(--duration-fast) var(--ease-out);background:0 0;border:none;border-bottom:2px solid #0000;font-size:.75rem;font-weight:500}.demo-tab:hover{color:var(--color-text);background:var(--color-cream)}.demo-tab.active{color:var(--color-accent);border-bottom-color:var(--color-accent);background:var(--color-accent-dim)}.demo-panels{flex:1}.demo-panel{display:none}.demo-panel.active{animation:fadeSlideIn .3s var(--ease-out);display:block}@keyframes fadeSlideIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.demo-container{background:var(--color-paper);border:none;border-radius:0;overflow:hidden}.demo-header{padding:var(--spacing-sm) var(--spacing-md);background:var(--color-paper);border-bottom:1px solid var(--color-mist);justify-content:center;align-items:center;min-height:48px;display:flex}.demo-toggle{align-items:center;gap:var(--spacing-md);display:flex}.demo-toggle-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--color-ash);transition:color var(--duration-fast) var(--ease-out);cursor:pointer;font-size:.6875rem;font-weight:600}.demo-toggle-label:hover{color:var(--color-text)}.demo-toggle-label.active{color:var(--color-accent)}.demo-toggle-switch{background:var(--color-mist);cursor:pointer;width:44px;height:24px;transition:background var(--duration-fast) var(--ease-out);font:inherit;border:1px solid #0000;border-radius:12px;padding:0;position:relative}.demo-toggle-switch:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}.demo-toggle-switch:hover{border-color:var(--color-ash)}.demo-toggle-switch:after{content:"";background:var(--color-paper);width:16px;height:16px;transition:transform var(--duration-base) var(--ease-spring);border-radius:50%;position:absolute;top:3px;left:3px;box-shadow:0 1px 4px #00000026}.demo-toggle-switch.active{background:var(--color-accent)}.demo-toggle-switch.active:after{transform:translate(20px)}.demo-viewport{padding:var(--spacing-xl);background:var(--color-cream);min-height:280px;transition:background var(--duration-base) var(--ease-out);justify-content:center;align-items:center;display:flex}.demo-viewport[data-state=after]{background:var(--color-paper)}.demo-caption{padding:var(--spacing-sm) var(--spacing-md);font-family:var(--font-mono);letter-spacing:.03em;color:var(--color-ash);background:var(--color-paper);text-align:center;font-size:.6875rem}.uxw-demo{width:100%;max-width:320px;padding:var(--spacing-lg);background:var(--color-paper);border:1px solid var(--color-mist);text-align:center;border-radius:6px}.uxw-error-icon{margin-bottom:var(--spacing-sm);font-size:2rem}.uxw-error-title{color:#c00;margin-bottom:var(--spacing-xs);font-weight:600}.uxw-error-text{color:var(--color-ash);font-size:.875rem}.uxw-error-action{margin-top:var(--spacing-sm);color:var(--color-accent);cursor:pointer;font-size:.875rem;text-decoration:underline}.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)}.uxw-button-context{color:var(--color-charcoal);margin-bottom:var(--spacing-md);font-size:.875rem;font-weight:500}.uxw-button-row{gap:var(--spacing-sm);justify-content:center;display:flex}.uxw-btn{padding:var(--spacing-xs) var(--spacing-md);cursor:pointer;border:none;border-radius:4px;font-size:.875rem;font-weight:500}.uxw-btn-primary{background:var(--color-text);color:var(--color-paper)}.uxw-btn-secondary{color:var(--color-ash);border:1px solid var(--color-mist);background:0 0}.uxw-btn-danger{color:#fff;background:#c00}.uxw-empty-icon{margin-bottom:var(--spacing-sm);opacity:.4;font-size:2.5rem}.uxw-empty-title{color:var(--color-ash);font-weight:500}.uxw-empty-text{color:var(--color-charcoal);margin-top:var(--spacing-xs);font-size:.875rem}.uxw-empty-action{margin-top:var(--spacing-md)}.uxw-empty-after .uxw-empty-icon{opacity:1}.uxw-empty-after .uxw-empty-title{color:var(--color-text)}.spatial-demo{width:100%;max-width:340px;padding:var(--spacing-md);background:var(--color-paper);border:1px solid var(--color-mist);border-radius:6px}.spatial-grid-before{flex-wrap:wrap;gap:6px;display:flex}.spatial-grid-after{gap:var(--spacing-sm);grid-template-columns:1fr 1fr;display:grid}.spatial-card-item{padding:var(--spacing-sm);background:var(--color-bg);border:1px solid var(--color-mist);color:var(--color-charcoal);text-align:center;border-radius:4px;font-size:.8125rem}.spatial-grid-after .spatial-card-item{width:auto!important}.spatial-hierarchy-before .spatial-h-title,.spatial-hierarchy-before .spatial-h-subtitle,.spatial-hierarchy-before .spatial-h-cta,.spatial-hierarchy-before .spatial-h-link{margin-bottom:var(--spacing-xs);color:var(--color-charcoal);font-size:.9375rem}.spatial-hierarchy-after .spatial-h-title{font-family:var(--font-display);margin-bottom:var(--spacing-xs);color:var(--color-text);font-size:1.75rem;font-style:italic;font-weight:300}.spatial-hierarchy-after .spatial-h-subtitle{text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);margin-bottom:var(--spacing-md);font-size:.6875rem}.spatial-hierarchy-after .spatial-h-cta{padding:var(--spacing-sm) var(--spacing-lg);background:var(--color-text);color:var(--color-paper);margin-bottom:var(--spacing-sm);border-radius:4px;font-size:.875rem;font-weight:500;display:inline-block}.spatial-hierarchy-after .spatial-h-link{color:var(--color-ash);font-size:.75rem}.spatial-whitespace-before{padding:var(--spacing-xs)!important}.spatial-whitespace-before .spatial-ws-title{margin-bottom:2px;font-size:1rem;font-weight:600}.spatial-whitespace-before .spatial-ws-price{color:var(--color-ash);margin-bottom:4px;font-size:.875rem}.spatial-whitespace-before .spatial-ws-features{color:var(--color-ash);margin-bottom:6px;font-size:.75rem}.spatial-whitespace-before .spatial-ws-btn{background:var(--color-text);width:100%;color:var(--color-paper);cursor:pointer;border:none;border-radius:3px;padding:6px;font-size:.75rem}.spatial-whitespace-after{padding:var(--spacing-lg)!important}.spatial-whitespace-after .spatial-ws-title{font-family:var(--font-display);margin-bottom:var(--spacing-sm);font-size:1.5rem;font-weight:400}.spatial-whitespace-after .spatial-ws-price{color:var(--color-text);margin-bottom:var(--spacing-sm);font-size:1.25rem;font-weight:600}.spatial-whitespace-after .spatial-ws-features{color:var(--color-ash);margin-bottom:var(--spacing-lg);font-size:.8125rem;line-height:1.6}.spatial-whitespace-after .spatial-ws-btn{width:100%;padding:var(--spacing-sm);background:var(--color-text);color:var(--color-paper);cursor:pointer;border:none;border-radius:4px;font-size:.875rem;font-weight:500}.motion-demo{align-items:center;gap:var(--spacing-sm);flex-direction:column;width:100%;max-width:280px;display:flex}.motion-stagger-demo{align-items:stretch}.motion-list-item{align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-md);background:var(--color-bg);border:1px solid var(--color-mist);color:var(--color-charcoal);border-radius:4px;font-size:.875rem;display:flex}.motion-dot{background:var(--color-accent);border-radius:50%;width:8px;height:8px}.demo-viewport[data-state=after] .motion-list-item{opacity:0;animation:.35s cubic-bezier(.16,1,.3,1) forwards staggerIn;transform:translateY(12px)}.demo-viewport[data-state=after] .motion-list-item:first-child{animation-delay:0s}.demo-viewport[data-state=after] .motion-list-item:nth-child(2){animation-delay:50ms}.demo-viewport[data-state=after] .motion-list-item:nth-child(3){animation-delay:.1s}.demo-viewport[data-state=after] .motion-list-item:nth-child(4){animation-delay:.15s}@keyframes staggerIn{to{opacity:1;transform:translateY(0)}}.motion-btn{cursor:pointer;border:none;border-radius:4px;padding:12px 24px;font-size:.9375rem;font-weight:500}.motion-btn-before{background:var(--color-charcoal);color:var(--color-paper)}.motion-btn-after{background:var(--color-text);color:var(--color-paper);transition:transform .2s cubic-bezier(.34,1.56,.64,1),box-shadow .2s}.motion-btn-after:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000026}.motion-btn-after:active{transform:translateY(0)scale(.98)}.motion-card{padding:var(--spacing-md);background:var(--color-bg);border:1px solid var(--color-mist);text-align:center;border-radius:6px;min-width:140px}.motion-card-icon{margin-bottom:var(--spacing-xs);font-size:1.5rem}.motion-card-text{color:var(--color-charcoal);font-size:.8125rem}.motion-card-after{transition:all .3s cubic-bezier(.34,1.56,.64,1)}.demo-viewport[data-state=after] .motion-card-after{background:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.demo-viewport[data-state=after] .motion-card-after{background:color-mix(in oklch, var(--color-accent) 10%, var(--color-paper))}}.demo-viewport[data-state=after] .motion-card-after{border-color:var(--color-accent)}.demo-viewport[data-state=after] .motion-card-after .motion-card-icon{animation:.4s cubic-bezier(.34,1.56,.64,1) checkPop}@keyframes checkPop{50%{transform:scale(1.3)}}.typo-demo{text-align:left;width:100%;max-width:320px}.typo-pairing-before{font-family:Inter,system-ui,sans-serif}.typo-pairing-before .typo-heading{margin-bottom:var(--spacing-xs);font-size:1.5rem;font-weight:600}.typo-pairing-before .typo-body{color:var(--color-ash);font-size:.9375rem;line-height:1.5}.typo-pairing-after .typo-heading{font-family:var(--font-display);letter-spacing:-.02em;margin-bottom:var(--spacing-sm);color:var(--color-text);font-size:2rem;font-style:italic;font-weight:300}.typo-pairing-after .typo-body{font-family:var(--font-body);color:var(--color-charcoal);font-size:.9375rem;line-height:1.7}.typo-hierarchy-before .typo-h1{margin-bottom:4px;font-size:1.125rem;font-weight:600}.typo-hierarchy-before .typo-meta{color:var(--color-ash);margin-bottom:var(--spacing-xs);font-size:.9375rem}.typo-hierarchy-before .typo-p{color:var(--color-charcoal);font-size:.875rem;line-height:1.5}.typo-hierarchy-after .typo-h1{font-family:var(--font-display);letter-spacing:-.03em;margin-bottom:2px;font-size:2.25rem;font-weight:300;line-height:1.1}.typo-hierarchy-after .typo-meta{text-transform:uppercase;letter-spacing:.12em;color:var(--color-accent);margin-bottom:var(--spacing-md);font-size:.6875rem}.typo-hierarchy-after .typo-p{color:var(--color-ash);font-size:.9375rem;line-height:1.7}.int-demo{gap:var(--spacing-md);flex-direction:column;width:100%;max-width:280px;display:flex}.int-states-demo{gap:var(--spacing-lg)}.int-state-row{align-items:center;gap:var(--spacing-md);display:flex}.int-state-label{text-transform:uppercase;letter-spacing:.08em;color:var(--color-ash);width:40px;font-size:.6875rem}.int-btn{padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;border-radius:4px;flex:1;font-size:.875rem;font-weight:500}.int-btn-poor{background:var(--color-charcoal);color:var(--color-paper);border:none}.int-btn-good{background:var(--color-text);color:var(--color-paper);border:2px solid #0000;transition:all .15s}.int-btn-good:hover{background:var(--color-charcoal)}.int-btn-good:focus{border-color:var(--color-accent);box-shadow:0 0 0 3px var(--color-accent);outline:none}@supports (color:color-mix(in lab, red, red)){.int-btn-good:focus{box-shadow:0 0 0 3px color-mix(in oklch, var(--color-accent) 25%, transparent)}}.int-btn-good:active{transform:scale(.98)}.int-aff-item{padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;border-radius:4px;font-size:.875rem}.int-aff-poor{color:var(--color-charcoal)}.int-aff-good{color:var(--color-accent);text-underline-offset:2px;text-decoration:underline}.int-aff-good:after{content:" →"}.int-affordance-after .int-aff-item{background:var(--color-bg);border:1px solid var(--color-mist);color:var(--color-accent);text-underline-offset:2px;text-decoration:underline;transition:background .15s}.int-affordance-after .int-aff-item:hover{background:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.int-affordance-after .int-aff-item:hover{background:color-mix(in oklch, var(--color-accent) 5%, var(--color-paper))}}.int-affordance-after .int-aff-item:after{content:" →"}.int-feedback-before,.int-feedback-after{align-items:center;gap:var(--spacing-md);flex-direction:row;display:flex}.int-fb-btn{cursor:pointer;border:none;border-radius:50%;justify-content:center;align-items:center;width:48px;height:48px;display:flex}.int-fb-btn svg{width:22px;height:22px}.int-fb-silent{background:var(--color-mist);color:var(--color-ash)}.int-fb-active{background:var(--color-charcoal);color:var(--color-paper);transition:all .15s cubic-bezier(.34,1.56,.64,1)}.int-fb-active:hover{transform:scale(1.1)}.int-fb-active:active{transform:scale(.95)}.int-fb-active.liked{background:var(--color-accent);animation:.35s cubic-bezier(.34,1.56,.64,1) heartPop}@keyframes heartPop{50%{transform:scale(1.25)}}.int-fb-label{color:var(--color-charcoal);font-size:.875rem}.color-demo{width:100%;max-width:300px}.color-palette-before,.color-palette-after{gap:var(--spacing-xs);padding:var(--spacing-md);background:var(--color-paper);border:1px solid var(--color-mist);border-radius:6px;flex-wrap:wrap;display:flex}.color-swatch{border-radius:4px;width:40px;height:40px;transition:background .2s}.color-card{width:100%;margin-top:var(--spacing-sm);padding:var(--spacing-sm);background:var(--color-paper);border:1px solid var(--color-mist);border-radius:4px;flex-direction:column;gap:4px;display:flex}.color-card span{font-size:.8125rem;font-weight:500;transition:color .2s}.color-card button{cursor:pointer;border:none;border-radius:3px;padding:6px;font-size:.75rem;font-weight:500;transition:all .2s}.color-palette-before .swatch-1{background:#ff6b6b}.color-palette-before .swatch-2{background:#4ecdc4}.color-palette-before .swatch-3{background:#ffe66d}.color-palette-before .swatch-4{background:#95e1d3}.color-palette-before .swatch-5{background:#f38181}.color-palette-before .card-title{color:#ff6b6b}.color-palette-before .card-subtitle{color:#4ecdc4}.color-palette-before .card-btn{color:#333;background:#ffe66d}.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)}.color-accent-card{padding:var(--spacing-md);border-radius:6px}.color-accent-before .color-accent-card{background:#f5f5f5;border:1px solid #e0e0e0}.color-accent-before .color-accent-title{color:#333;margin-bottom:4px;font-weight:600}.color-accent-before .color-accent-text{color:#666;margin-bottom:var(--spacing-sm);font-size:.8125rem}.color-accent-before .color-accent-btn{width:100%;padding:var(--spacing-xs);color:#fff;cursor:pointer;background:#333;border:none;border-radius:4px;font-size:.8125rem}.color-accent-after .color-accent-card{background:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.color-accent-after .color-accent-card{background:color-mix(in oklch, var(--color-accent) 8%, var(--color-paper))}}.color-accent-after .color-accent-card{border:1px solid var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.color-accent-after .color-accent-card{border:1px solid color-mix(in oklch, var(--color-accent) 20%, var(--color-paper))}}.color-accent-after .color-accent-title{color:var(--color-text);margin-bottom:4px;font-weight:600}.color-accent-after .color-accent-text{color:var(--color-ash);margin-bottom:var(--spacing-sm);font-size:.8125rem}.color-accent-after .color-accent-btn{width:100%;padding:var(--spacing-xs);background:var(--color-accent);color:var(--color-paper);cursor:pointer;border:none;border-radius:4px;font-size:.8125rem;font-weight:500}.color-contrast-static{gap:var(--spacing-sm);flex-direction:column;display:flex}.contrast-example{padding:var(--spacing-md);text-align:center;border-radius:6px}.contrast-fail{color:#a0a0a0;background:#f0f0f0}.contrast-pass{background:var(--color-charcoal);color:var(--color-paper)}.contrast-badge{text-transform:uppercase;letter-spacing:.1em;border-radius:2px;margin-bottom:4px;padding:2px 6px;font-size:.5625rem;font-weight:600;display:inline-block}.contrast-fail .contrast-badge{background:#ddd}.contrast-pass .contrast-badge{background:var(--color-accent);color:var(--color-paper)}.contrast-text{margin-bottom:2px;font-size:1rem;font-weight:500}.contrast-ratio{opacity:.7;font-size:.6875rem}.resp-demo{width:100%;max-width:340px}.resp-touch-demo{gap:var(--spacing-lg);flex-direction:column;display:flex}.resp-touch-row{align-items:center;gap:var(--spacing-md);display:flex}.resp-label{text-transform:uppercase;letter-spacing:.08em;color:var(--color-ash);width:70px;font-size:.6875rem}.resp-touch-targets{gap:4px;display:flex}.resp-touch-targets button{cursor:pointer;border:none;border-radius:4px;font-weight:500}.resp-touch-bad button{background:var(--color-mist);width:24px;height:24px;color:var(--color-ash);font-size:.75rem}.resp-touch-good button{background:var(--color-text);width:44px;height:44px;color:var(--color-paper);font-size:1rem}.resp-fluid-demo{padding:var(--spacing-md);background:var(--color-bg);border:1px solid var(--color-mist);border-radius:6px}.resp-fluid-container{gap:var(--spacing-md);flex-direction:column;display:flex}.resp-fluid-fixed,.resp-fluid-adaptive{color:var(--color-ash);font-size:.75rem}.resp-fluid-fixed span,.resp-fluid-adaptive span{margin-bottom:4px;display:block}.resp-fluid-bar{background:var(--color-mist);border-radius:4px;height:24px}.resp-fluid-adaptive .resp-fluid-bar{background:var(--color-accent)}.resp-adapt-demo{gap:var(--spacing-sm);align-items:flex-end;display:flex}.resp-device{text-align:center}.resp-device>span{color:var(--color-ash);text-transform:uppercase;letter-spacing:.08em;margin-top:4px;font-size:.625rem;display:block}.resp-device-screen{background:var(--color-paper);border:2px solid var(--color-mist);border-radius:4px;flex-direction:column;gap:3px;padding:4px;display:flex}.resp-device-mobile .resp-device-screen{width:50px;height:80px}.resp-device-tablet .resp-device-screen{width:80px;height:60px}.resp-device-desktop .resp-device-screen{width:120px;height:70px}.resp-block{background:var(--color-mist);border-radius:2px}.resp-block-row{flex:1;gap:3px;display:flex}.resp-header{background:var(--color-charcoal);height:16px}.resp-sidebar{background:var(--color-charcoal);width:30%}.resp-content{flex:1}@keyframes fadeIn{to{opacity:1}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}*,:before,:after{box-sizing:border-box}*{margin:0}img,picture,video,canvas,svg{max-width:100%;display:block}button,input,textarea,select{font:inherit}:root{--font-display:"Cormorant Garamond", Georgia, serif;--font-body:"Instrument Sans", system-ui, sans-serif;--font-mono:"Space Grotesk", monospace;--spacing-xs:8px;--spacing-sm:16px;--spacing-md:24px;--spacing-lg:32px;--spacing-xl:48px;--spacing-2xl:80px;--spacing-3xl:120px;--width-max:1400px;--width-content:900px;--ease-out:cubic-bezier(.16, 1, .3, 1);--ease-in-out:cubic-bezier(.65, 0, .35, 1);--ease-spring:cubic-bezier(.34, 1.56, .64, 1);--duration-fast:.15s;--duration-base:.3s;--duration-slow:.6s;--duration-slower:.8s;--duration-slowest:1.2s;--color-ink:oklch(10% 0 0);--color-text:oklch(10% 0 0);--color-paper:oklch(98% 0 0);--color-cream:oklch(96% .005 350);--color-charcoal:oklch(25% 0 0);--color-ash:oklch(55% 0 0);--color-mist:oklch(92% 0 0);--color-bg:oklch(96% .005 350);--color-accent:oklch(60% .25 350);--color-accent-hover:oklch(52% .25 350);--color-accent-dim:oklch(60% .25 350/.15);--color-accent-soft:oklch(60% .25 350/.25);--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}.skip-link{z-index:10000;padding:var(--spacing-sm) var(--spacing-lg);background:var(--color-ink);color:var(--color-paper);border-radius:0 0 8px 8px;font-weight:600;text-decoration:none;transition:top .2s;position:absolute;top:-100%;left:50%;transform:translate(-50%)}.skip-link:focus{outline:2px solid var(--color-accent);outline-offset:2px;top:0}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizelegibility;overflow-x:clip}body{font-family:var(--font-body);color:var(--color-text);background:var(--color-paper);min-height:100dvh;font-size:16px;line-height:1.625;overflow-x:clip}h1,h2,h3,h4,h5,h6{font-family:var(--font-display);letter-spacing:-.02em;color:var(--color-ink);font-weight:400;line-height:1.1}a{color:var(--color-accent);text-underline-offset:2px;transition:color var(--duration-fast) var(--ease-out), text-decoration-color var(--duration-fast) var(--ease-out);text-decoration:underline;text-decoration-thickness:1px}a:hover{color:var(--color-accent-hover);text-decoration-thickness:2px}.btn,.footer-logo,[class*=nav-item]{text-decoration:none}strong{color:var(--color-ink);font-weight:600}code{font-family:var(--font-mono);background:var(--color-accent-dim);color:var(--color-accent);border-radius:4px;padding:.15em .4em;font-size:.9em}::selection{background:var(--color-accent-soft);color:var(--color-ink)}.grain-overlay{pointer-events:none;z-index:9999;opacity:.03;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");background-repeat:repeat;position:fixed;inset:0}.site-content{max-width:var(--width-max);padding:0 var(--spacing-lg);margin:0 auto}@media (max-width:768px){.site-content{padding:0 var(--spacing-md)}}.section-header{margin-bottom:var(--spacing-lg);position:relative}.section-number{font-family:var(--font-mono);letter-spacing:.05em;color:var(--color-ash);margin-bottom:var(--spacing-xs);text-transform:uppercase;font-size:.625rem;font-weight:500;display:block}.section-title{margin:0;font-size:clamp(1.75rem,4vw,2.5rem);font-weight:400;line-height:1.2}.section-subtitle{color:var(--color-charcoal);margin-top:var(--spacing-sm);max-width:55ch;font-size:1rem;line-height:1.6}.cheatsheet-link{color:var(--color-accent);margin-left:.5em;font-size:.875rem;text-decoration:none}.cheatsheet-link:hover{text-decoration:underline}.section-lead{color:var(--color-charcoal);max-width:55ch;margin-bottom:var(--spacing-lg);font-size:1rem;line-height:1.6}.hero-combined{min-height:100dvh;padding:var(--spacing-2xl) 0;background:var(--color-paper);flex-direction:column;justify-content:center;display:flex;position:relative}.github-link{top:var(--spacing-md);right:var(--spacing-lg);z-index:10;color:var(--color-ash);transition:color .2s;position:absolute}.github-link:hover{color:var(--color-ink)}.github-link svg{width:28px;height:28px}.hero-combined-container{max-width:var(--width-max);padding:0 var(--spacing-lg);gap:var(--spacing-xl);grid-template-columns:1fr 1fr;align-items:center;width:100%;margin:0 auto;display:grid}@media (max-width:1024px){.hero-combined-container{gap:var(--spacing-lg);text-align:center;grid-template-columns:1fr}}.hero-combined-left{gap:var(--spacing-md);flex-direction:column;display:flex}@media (max-width:1024px){.hero-combined-left{align-items:center}}.hero-title-combined{font-family:var(--font-display);letter-spacing:-.02em;color:var(--color-ink);margin:0;font-size:clamp(2.5rem,7vw,4.5rem);font-style:italic;font-weight:300;line-height:1}.hero-tagline-combined{font-family:var(--font-display);color:var(--color-charcoal);margin:0;font-size:clamp(1.125rem,2.5vw,1.75rem);font-style:italic;font-weight:400;line-height:1.3}.hero-hook-text{color:var(--color-charcoal);max-width:45ch;margin:0;font-size:1rem;line-height:1.6}.hero-included-box{border:1px solid var(--color-mist);background:0 0;flex-direction:column;gap:6px;max-width:45ch;padding:10px 14px;display:flex}.hero-included-title{font-family:var(--font-body);text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.5625rem;font-weight:500}.hero-included-items{color:var(--color-charcoal);flex-wrap:wrap;align-items:center;gap:6px;font-size:.8125rem;line-height:1.5;display:flex}.hero-included-items em{font-style:normal;font-family:var(--font-mono);font-size:.75rem}.hero-included-sep{color:var(--color-mist)}@media (max-width:500px){.hero-included-items{flex-direction:column;align-items:flex-start;gap:4px}.hero-included-sep{display:none}}.hero-cta-group{align-items:center;gap:var(--spacing-lg);margin-top:var(--spacing-sm);display:flex}@media (max-width:600px){.hero-cta-group{gap:var(--spacing-md);flex-direction:column}}.hero-cta-combined{padding:var(--spacing-sm) var(--spacing-xl);font-family:var(--font-body);letter-spacing:.05em;text-transform:uppercase;color:var(--color-paper);background:var(--color-ink);border:none;font-size:.9rem;font-weight:500;text-decoration:none;transition:transform .2s,background .2s;display:inline-block}.hero-cta-combined:hover{background:var(--color-accent);color:var(--color-paper);transform:translateY(-2px)}.hero-logos-inline{align-items:center;gap:var(--spacing-sm);display:flex}.hero-logos-inline .hero-logos-label{color:var(--color-ash);letter-spacing:.03em;font-size:.6875rem}.hero-logos-inline .hero-logos-row{align-items:center;gap:8px;display:flex}.hero-logos-inline .hero-logos-row img{opacity:.7;border-radius:4px;transition:opacity .2s}.hero-logos-inline .hero-logos-row img:hover{opacity:1}.hero-combined-right{justify-content:center;display:flex}.hero-combined-right .split-comparison{width:100%;max-width:520px}.hero-combined-right .split-container{max-width:100%}.hero-bias-tags{align-items:center;gap:var(--spacing-xs);margin-top:var(--spacing-lg);padding-top:var(--spacing-md);border-top:1px solid var(--color-mist);max-width:var(--width-max);width:100%;padding-bottom:var(--spacing-md);flex-direction:column;margin-left:auto;margin-right:auto;display:flex}.problem-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.problem-content{gap:var(--spacing-xl);display:grid}.split-comparison{width:100%;max-width:600px;margin:-20px auto;padding:20px;position:relative}.split-container{background:var(--color-cream);border:1px solid var(--color-mist);cursor:ew-resize;-webkit-user-select:none;user-select:none;border-radius:12px;width:100%;max-width:500px;height:380px;margin:0 auto;position:relative;overflow:hidden}.split-before,.split-after{justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.split-before{z-index:1}.split-content{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.split-after{clip-path:polygon(78% 0%,100% 0%,100% 100%,62% 100%);z-index:2;background:var(--color-paper)}.split-divider{background:var(--color-accent);pointer-events:none;z-index:3;width:3px;position:absolute;top:0;bottom:0;left:70%;transform:translate(-50%)skew(-10deg);box-shadow:0 0 20px #00000026}.split-label{letter-spacing:.08em;text-transform:uppercase;color:var(--color-paper);background:var(--color-accent);white-space:nowrap;border-radius:4px;padding:6px 14px;font-size:.6875rem;font-weight:600;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)skew(10deg);box-shadow:0 2px 8px #0003}.slop-card{background:linear-gradient(135deg,#f5f3ff 0%,#ede9fe 50%,#ddd6fe 100%);border-radius:16px;flex-direction:column;width:280px;height:280px;padding:24px;font-family:Inter,system-ui,sans-serif;display:flex;box-shadow:0 4px 6px -1px #0000001a}.slop-header{align-items:center;gap:12px;margin-bottom:16px;display:flex}.slop-avatar{background:linear-gradient(135deg,#8b5cf6,#7c3aed);border-radius:50%;flex-shrink:0;width:40px;height:40px}.slop-text{flex:1}.slop-title{color:#1f2937;margin-bottom:2px;font-size:14px;font-weight:600}.slop-subtitle{color:#6b7280;font-size:12px}.slop-body{color:#4b5563;flex:1;margin-bottom:auto;font-size:13px;line-height:1.5}.slop-button{color:#fff;cursor:pointer;background:linear-gradient(135deg,#8b5cf6,#7c3aed);border:none;border-radius:8px;width:100%;margin-top:auto;padding:10px 20px;font-family:Inter,system-ui,sans-serif;font-size:13px;font-weight:500}.slop-callouts{pointer-events:none;position:absolute;inset:0}.slop-callout{text-transform:uppercase;letter-spacing:.06em;color:var(--color-accent);background:var(--color-paper);border:1px solid var(--color-accent);white-space:nowrap;opacity:0;animation:calloutFadeIn .4s var(--ease-out) forwards;border-radius:3px;padding:4px 8px;font-size:.625rem;font-weight:600;position:absolute;box-shadow:0 2px 8px #0000001a}.slop-callout[data-point=font]{animation-delay:.1s;top:15%;right:5%}.slop-callout[data-point=gradient]{animation-delay:.25s;top:40%;left:5%}.slop-callout[data-point=copy]{animation-delay:.4s;bottom:35%;right:8%}.slop-callout[data-point=rounded]{animation-delay:.55s;bottom:12%;left:10%}@keyframes calloutFadeIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.impeccable-card{background:var(--color-paper);border:1px solid var(--color-mist);width:280px;height:300px;padding:var(--spacing-lg);text-align:left;flex-direction:column;display:flex}.impeccable-eyebrow{font-family:var(--font-mono);letter-spacing:.15em;text-transform:uppercase;color:var(--color-accent);margin-bottom:var(--spacing-xs);font-size:.625rem;font-weight:500}.impeccable-title{font-family:var(--font-display);color:var(--color-ink);margin-bottom:var(--spacing-sm);font-size:1.75rem;font-style:italic;font-weight:300;line-height:1.1}.impeccable-body{color:var(--color-ash);flex:1;margin-bottom:auto;font-size:.875rem;line-height:1.6}.impeccable-button{margin-top:var(--spacing-sm);background:var(--color-ink);color:var(--color-paper);font-family:var(--font-body);letter-spacing:.03em;cursor:pointer;transition:all var(--duration-base) var(--ease-out);border:none;align-self:flex-start;padding:.625rem 1.5rem;font-size:.8125rem;font-weight:500;display:inline-flex}.impeccable-button:hover{background:var(--color-accent)}.split-labels{justify-content:center;gap:var(--spacing-xl);margin-top:var(--spacing-md);display:flex}.split-label-item{align-items:center;gap:var(--spacing-xs);color:var(--color-ash);font-size:.8125rem;display:flex}.split-label-dot{background:var(--color-mist);border-radius:50%;width:8px;height:8px}.split-label-dot--accent{background:var(--color-accent)}.solution-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.solution-content{gap:var(--spacing-lg);display:grid}.solution-content .section-lead{margin-bottom:0}.solution-visual{gap:var(--spacing-lg);grid-template-columns:1fr auto 1fr;align-items:stretch;display:grid}@media (max-width:900px){.solution-visual{gap:var(--spacing-md);grid-template-columns:1fr}}.solution-visual-interactive{background:var(--color-paper);border:1px solid var(--color-mist);border-radius:8px;width:100%;min-height:380px;position:relative;overflow:hidden}.solution-pillar{background:var(--color-cream);border:1px solid var(--color-mist);padding:var(--spacing-lg);transition:all var(--duration-base) var(--ease-out)}.solution-pillar:hover{border-color:var(--color-accent);box-shadow:0 20px 60px var(--color-accent-dim);transform:translateY(-4px)}.pillar-header{text-align:center;margin-bottom:var(--spacing-lg);padding-bottom:var(--spacing-md);border-bottom:1px solid var(--color-mist)}.pillar-icon{background:var(--color-accent-dim);width:56px;height:56px;color:var(--color-accent);margin-bottom:var(--spacing-sm);border-radius:50%;justify-content:center;align-items:center;display:inline-flex}.pillar-title{font-family:var(--font-display);margin:0 0 var(--spacing-xs);font-size:1.75rem;font-weight:400}.pillar-subtitle{color:var(--color-ash);margin:0;font-size:.875rem}.pillar-content{gap:var(--spacing-sm);flex-direction:column;display:flex}.pillar-item{padding:var(--spacing-sm);background:var(--color-paper);transition:all var(--duration-fast) var(--ease-out);border-radius:4px;justify-content:space-between;align-items:center;display:flex}.pillar-item:hover{background:var(--color-accent-dim)}.pillar-item-name{color:var(--color-ink);font-size:.9375rem;font-weight:500}.pillar-item-code{font-family:var(--font-mono);color:var(--color-accent);background:0 0;padding:0;font-size:.875rem;font-weight:500}.pillar-item-desc{color:var(--color-ash);font-size:.75rem}.pillar-item--more{color:var(--color-accent);border:1px dashed var(--color-mist);background:0 0;justify-content:center;font-size:.8125rem;font-weight:500}.solution-connector{justify-content:center;align-items:center;display:flex}.connector-plus{font-family:var(--font-display);color:var(--color-accent);opacity:.5;font-size:3rem;font-weight:300}@media (max-width:900px){.solution-connector{padding:var(--spacing-sm) 0}.connector-plus{font-size:2rem}}.skills-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.skills-gallery{gap:var(--spacing-xl);grid-template-columns:200px 1fr;align-items:start;display:grid}@media (max-width:968px){.skills-gallery{gap:var(--spacing-lg);grid-template-columns:1fr}}.skills-nav{top:var(--spacing-lg);flex-direction:column;gap:2px;display:flex;position:sticky}@media (max-width:968px){.skills-nav{gap:var(--spacing-xs);flex-flow:wrap;position:static}}.skill-nav-item{padding:var(--spacing-sm) var(--spacing-md);color:var(--color-ash);font-family:var(--font-body);cursor:pointer;text-align:left;background:0 0;border:none;border-left:2px solid #0000;font-size:.9375rem;font-weight:400;text-decoration:none;transition:all .2s;display:block}.skill-nav-item:hover{color:var(--color-text);background:var(--color-cream)}.skill-nav-item.active{color:var(--color-accent);border-left-color:var(--color-accent);background:var(--color-accent-dim);font-weight:500}@media (max-width:968px){.skill-nav-item{padding:var(--spacing-xs) var(--spacing-md);border-bottom:2px solid #0000;border-left:none}.skill-nav-item.active{border-bottom-color:var(--color-accent)}}.skills-showcase{gap:var(--spacing-lg);grid-template-columns:1.2fr 1fr;align-items:start;display:grid}@media (max-width:1100px){.skills-showcase{grid-template-columns:1fr}}.loading-state{padding:var(--spacing-xl);text-align:center;color:var(--color-ash);font-style:italic}.mobile-commands-layout{display:none}@media (max-width:900px){.mobile-commands-layout{gap:var(--spacing-md);flex-direction:column;display:flex}.commands-container{display:none}}.mobile-carousel-wrapper{-webkit-overflow-scrolling:touch;scrollbar-width:none;padding:var(--spacing-xs) 0;overflow-x:auto}.mobile-carousel-wrapper::-webkit-scrollbar{display:none}.mobile-carousel{gap:var(--spacing-xs);padding-right:var(--spacing-md);display:flex}.mobile-cmd-pill{padding:var(--spacing-sm) var(--spacing-md);min-height:44px;font-family:var(--font-mono);color:var(--color-ash);background:var(--color-cream);border:1px solid var(--color-mist);cursor:pointer;white-space:nowrap;border-radius:100px;flex-shrink:0;font-size:.8125rem;font-weight:500;transition:all .2s}.mobile-cmd-pill:hover{color:var(--color-charcoal);border-color:var(--color-charcoal)}.mobile-cmd-pill.active{color:var(--color-paper);background:var(--color-ink);border-color:var(--color-ink)}.mobile-demo-area{background:var(--color-cream);border:1px solid var(--color-mist);padding:var(--spacing-sm);border-radius:8px}.mobile-demo-area .demo-split-comparison{width:100%}.mobile-demo-area .split-container{width:100%;max-width:100%;height:320px}.mobile-demo-area .demo-caption{margin-top:var(--spacing-sm);font-size:.75rem}.mobile-info-area{padding-top:var(--spacing-sm)}.mobile-cmd-info{padding:var(--spacing-sm) 0;display:none}.mobile-cmd-info.active{display:block}.mobile-cmd-name{font-family:var(--font-mono);color:var(--color-ink);margin:0 0 var(--spacing-xs) 0;font-size:1.125rem;font-weight:600}.mobile-cmd-desc{color:var(--color-charcoal);margin:0;font-size:.875rem;line-height:1.5}.mobile-cmd-rel{margin-top:var(--spacing-xs);color:var(--color-ash);font-size:.75rem}.mobile-cmd-rel code{font-family:var(--font-mono);color:var(--color-ink)}.downloads-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.downloads-grid{gap:var(--spacing-lg);grid-template-columns:repeat(auto-fit,minmax(280px,1fr));display:grid}.download-card{text-align:center;padding:var(--spacing-lg);background:var(--color-cream);border:1px solid var(--color-mist);transition:all var(--duration-base) var(--ease-out);flex-direction:column;align-items:center;display:flex}.download-card:hover{border-color:var(--color-accent);box-shadow:0 20px 60px var(--color-accent-dim);transform:translateY(-4px)}.download-card-icon{margin-bottom:var(--spacing-sm)}.download-card-icon img{object-fit:contain;border-radius:8px;width:40px;height:40px}.download-card-title{font-family:var(--font-display);margin:0 0 var(--spacing-sm) 0;font-size:1.25rem;font-weight:400}.download-card-note{color:var(--color-ash);margin-bottom:var(--spacing-xs);font-size:.75rem}.download-card .btn{margin-top:var(--spacing-xs)}.install-command{align-items:center;gap:var(--spacing-xs);background:var(--color-paper);border:1px solid var(--color-mist);padding:var(--spacing-sm);margin-top:var(--spacing-sm);border-radius:6px;width:100%;display:flex}.install-command code{font-family:var(--font-mono);color:var(--color-ink);white-space:nowrap;text-overflow:ellipsis;background:0 0;flex:1;padding:0;font-size:.75rem;overflow:hidden}.copy-btn{border:1px solid var(--color-mist);width:28px;height:28px;color:var(--color-ash);cursor:pointer;transition:all var(--duration-fast) var(--ease-out);background:0 0;border-radius:4px;flex-shrink:0;justify-content:center;align-items:center;display:flex}.copy-btn:hover{background:var(--color-accent-dim);border-color:var(--color-accent);color:var(--color-accent)}.copy-btn.copied{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-paper)}.install-hint{color:var(--color-ash);margin:var(--spacing-xs) 0 0 0;font-size:.75rem}.install-hint code{font-family:var(--font-mono);background:var(--color-mist);border-radius:3px;padding:2px 5px;font-size:.6875rem}.download-card-details{width:100%;margin-top:var(--spacing-sm);text-align:left;font-size:.8125rem}.download-card-details summary{cursor:pointer;color:var(--color-ash);padding:var(--spacing-xs) 0;justify-content:center;align-items:center;gap:4px;font-size:.75rem;list-style:none;display:flex}.download-card-details summary:before{content:"▶";transition:transform var(--duration-fast) var(--ease-out);font-size:.5rem}.download-card-details[open] summary:before{transform:rotate(90deg)}.download-card-details summary::-webkit-details-marker{display:none}.download-card-details ol{margin:var(--spacing-sm) 0;padding-left:var(--spacing-md);color:var(--color-charcoal);line-height:1.6}.download-card-details li{margin-bottom:4px}.download-card-details code{font-family:var(--font-mono);background:var(--color-mist);border-radius:3px;padding:2px 5px;font-size:.6875rem}.download-card-details a{color:var(--color-accent);font-size:.75rem;text-decoration:none}.download-card-details a:hover{text-decoration:underline}.opensource-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist);text-align:center}.opensource-content{align-items:center;gap:var(--spacing-md);flex-direction:column;max-width:500px;margin:0 auto;display:flex}.opensource-title{font-size:clamp(1.5rem,4vw,2rem);font-weight:300}.opensource-desc{color:var(--color-ash);font-size:1.125rem;line-height:1.6}.site-footer{border-top:1px solid var(--color-mist);padding:var(--spacing-xl) var(--spacing-lg);background:var(--color-cream)}.footer-content{max-width:var(--width-max);justify-content:space-between;align-items:center;gap:var(--spacing-lg);flex-wrap:wrap;margin:0 auto;display:flex}@media (max-width:768px){.footer-content{text-align:center;flex-direction:column}}.footer-brand{gap:var(--spacing-xs);flex-direction:column;display:flex}.footer-logo{font-family:var(--font-display);color:var(--color-ink);font-size:1.25rem;font-weight:400}.footer-tagline{color:var(--color-ash);font-size:.875rem}.footer-links{gap:var(--spacing-lg);flex-wrap:wrap;display:flex}.footer-links a{color:var(--color-ash);transition:color var(--duration-fast) var(--ease-out);font-size:.875rem}.footer-links a:hover{color:var(--color-accent)}.footer-author{justify-content:center;align-items:center;gap:var(--spacing-md);width:100%;padding-top:var(--spacing-lg);margin-top:var(--spacing-md);border-top:1px solid var(--color-mist);flex-wrap:wrap;display:flex}.footer-author-label{color:var(--color-ash);font-size:.875rem}.footer-author-label a{color:var(--color-text);transition:color var(--duration-fast) var(--ease-out)}.footer-author-label a:hover{color:var(--color-accent)}.footer-author-links{align-items:center;gap:var(--spacing-sm);display:flex}.footer-social-link{width:36px;height:36px;color:var(--color-ash);transition:all var(--duration-fast) var(--ease-out);background:0 0;border-radius:50%;justify-content:center;align-items:center;text-decoration:none;display:flex}.footer-social-link:hover{color:var(--color-accent);background:var(--color-accent-dim)}.footer-author-divider{background:var(--color-mist);width:1px;height:20px;margin:0 var(--spacing-xs)}.footer-newsletter{color:var(--color-text);background:var(--color-paper);border:1px solid var(--color-mist);transition:all var(--duration-fast) var(--ease-out);border-radius:100px;align-items:center;gap:6px;padding:8px 14px;font-size:.875rem;font-weight:500;text-decoration:none;display:inline-flex}.footer-newsletter:hover{border-color:var(--color-accent);color:var(--color-accent)}.footer-newsletter svg{transition:transform var(--duration-fast) var(--ease-out)}.footer-newsletter:hover svg{transform:translate(3px)}@media (max-width:768px){.footer-author{gap:var(--spacing-sm);flex-direction:column}.footer-author-divider{display:none}}.btn{justify-content:center;align-items:center;gap:var(--spacing-xs);font-family:var(--font-body);letter-spacing:.03em;cursor:pointer;transition:all var(--duration-base) var(--ease-out);border:none;padding:1rem 2rem;font-size:.9375rem;font-weight:600;text-decoration:none;display:inline-flex;position:relative;overflow:hidden}.btn-primary{background:var(--color-ink);color:var(--color-paper)}.btn-primary:before{content:"";background:var(--color-accent);transition:transform var(--duration-base) var(--ease-out);z-index:0;position:absolute;inset:0;transform:translateY(100%)}.btn-primary:hover:before{transform:translateY(0)}.btn-primary:hover{color:var(--color-paper)}.btn-primary span,.btn-primary svg,.btn-primary:not(:has(span)){z-index:1;position:relative}.btn-secondary{color:var(--color-ink);border:1px solid var(--color-ink);background:0 0}.btn-secondary:hover{background:var(--color-ink);color:var(--color-paper)}.btn:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}.btn-primary:focus-visible{outline-color:var(--color-paper);box-shadow:0 0 0 4px var(--color-accent)}.btn-secondary:focus-visible{outline-color:var(--color-accent)}@keyframes revealUp{to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translate(-50%)translateY(0)}50%{transform:translate(-50%)translateY(-8px)}}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(4px)}}[data-reveal]{opacity:0;transition:opacity .8s var(--ease-out), transform .8s var(--ease-out);transform:translateY(30px)}[data-reveal].revealed{opacity:1;transform:translateY(0)}[data-reveal]:first-child{transition-delay:0s}[data-reveal]:nth-child(2){transition-delay:.1s}[data-reveal]:nth-child(3){transition-delay:.2s}[data-reveal]:nth-child(4){transition-delay:.3s}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}html{scroll-behavior:auto}.hero-canvas{display:none}.hero-scroll-indicator{opacity:1;animation:none}[data-reveal],.gallery-frame{opacity:1;transform:none}}.load-error{text-align:center;padding:var(--spacing-2xl) var(--spacing-lg);justify-content:center;align-items:center;gap:var(--spacing-md);background:var(--color-cream);border:1px solid var(--color-mist);border-radius:8px;flex-direction:column;display:flex}.load-error-icon{color:var(--color-accent);font-size:2.5rem}.load-error-title{font-family:var(--font-display);color:var(--color-ink);margin:0;font-size:1.5rem;font-weight:400}.load-error-text{color:var(--color-ash);max-width:40ch;font-size:1rem;line-height:1.5}.load-error-retry{margin-top:var(--spacing-sm)}.bias-tags{align-items:center;gap:var(--spacing-sm);margin-top:var(--spacing-lg);flex-direction:column;display:flex}.bias-tags-label{font-family:var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--color-ash);font-size:.6875rem;font-weight:500}.bias-tags-list{justify-content:center;gap:var(--spacing-xs);flex-wrap:wrap;display:flex}.bias-tag{background:var(--color-cream);border:1px solid var(--color-mist);color:var(--color-charcoal);transition:all var(--duration-fast) var(--ease-out);padding:6px 12px;font-size:.75rem;font-weight:500}.bias-tag:hover{border-color:var(--color-accent);color:var(--color-accent)}.antidote-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.patterns-categories{margin-bottom:var(--spacing-xl)}.pattern-tabs{gap:var(--spacing-xs);margin-bottom:var(--spacing-lg);flex-wrap:wrap;display:flex}.pattern-tab{font-family:var(--font-body);color:var(--color-ash);padding:var(--spacing-xs) var(--spacing-sm);cursor:pointer;transition:color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);background:0 0;border:none;border-bottom:2px solid #0000;font-size:.875rem}.pattern-tab:hover{color:var(--color-charcoal)}.pattern-tab.active{color:var(--color-ink);border-bottom-color:var(--color-accent);font-weight:500}.pattern-tab:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px;border-radius:4px}.pattern-panel{display:none}.pattern-panel.active{display:block}.pattern-columns{gap:var(--spacing-xl);grid-template-columns:1fr 1fr;display:grid}@media (max-width:768px){.pattern-columns{gap:var(--spacing-md);grid-template-columns:1fr}}.pattern-column-label{text-transform:uppercase;letter-spacing:.1em;margin-bottom:var(--spacing-sm);color:var(--color-ash);font-size:.6875rem;font-weight:600;display:block}.pattern-column--anti .pattern-column-label{color:var(--color-accent)}.pattern-column--do .pattern-column-label{color:var(--color-success,#22c55e)}.pattern-list{gap:var(--spacing-xs);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.pattern-item{padding-left:var(--spacing-md);font-size:.8125rem;line-height:1.5;position:relative}.pattern-item--anti{color:var(--color-ash)}.pattern-item--anti:before{content:"×";color:var(--color-accent);font-weight:600;position:absolute;left:0}.pattern-item--do{color:var(--color-charcoal)}.pattern-item--do:before{content:"✓";color:var(--color-success,#22c55e);font-weight:600;position:absolute;left:0}.contribute-inline{color:var(--color-ash);margin-top:var(--spacing-md);font-size:.875rem}.contribute-inline a{color:var(--color-accent);text-decoration:none}.contribute-inline a:hover{text-decoration:underline}.pillar-item--main{background:var(--color-accent-dim);border:1px solid var(--color-accent)}.pillar-item--main .pillar-item-name{color:var(--color-accent);font-size:1.125rem;font-weight:600}.pillar-item--ref{padding:var(--spacing-xs) var(--spacing-sm);background:0 0}.pillar-item-label{text-transform:uppercase;letter-spacing:.05em;color:var(--color-ash);font-size:.75rem;font-weight:500}.pillar-refs{gap:var(--spacing-xs);padding:0 var(--spacing-sm);flex-wrap:wrap;display:flex}.pillar-ref{text-transform:uppercase;letter-spacing:.03em;background:var(--color-paper);color:var(--color-ash);border:1px solid var(--color-mist);transition:all var(--duration-fast) var(--ease-out);border-radius:3px;padding:4px 10px;font-size:.6875rem;font-weight:500}.pillar-ref:hover{border-color:var(--color-accent);color:var(--color-accent)}.pillar-command-group{align-items:center;gap:var(--spacing-xs);padding:var(--spacing-sm);background:var(--color-paper);border-radius:4px;flex-wrap:wrap;display:flex}.pillar-group-label{text-transform:uppercase;letter-spacing:.05em;color:var(--color-ash);width:100%;margin-bottom:4px;font-size:.6875rem;font-weight:600}.pillar-command-group .pillar-item-code{background:var(--color-accent-dim);border-radius:3px;padding:4px 8px;font-size:.8125rem}.platforms-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.platforms-section .section-subtitle{max-width:60ch}.install-terminal{max-width:640px;margin:0 auto var(--spacing-xl)}.install-terminal .glass-terminal{height:auto}.install-terminal .terminal-body{flex-direction:column;padding:0;display:flex}.install-terminal-row{padding:var(--spacing-md) var(--spacing-lg);flex-direction:column;gap:6px;display:flex}.install-terminal-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.625rem;font-weight:600}.install-terminal-cmd{align-items:center;gap:var(--spacing-sm);display:flex}.install-terminal-cmd .terminal-prompt{flex-shrink:0}.install-terminal-cmd code{font-family:var(--font-mono);color:var(--color-ink);white-space:nowrap;text-overflow:ellipsis;background:0 0;flex:1;padding:0;font-size:.9375rem;overflow:hidden}.install-terminal-cmd .copy-btn{flex-shrink:0}.install-terminal-cmd .btn{padding:.5rem 1rem;font-size:.8125rem}.install-terminal-note{color:var(--color-ash);padding-left:calc(.75rem + var(--spacing-sm));font-size:.75rem}.install-terminal-note code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 5px;font-size:.6875rem}.install-terminal-divider{background:var(--color-mist);height:1px;margin:0}@media (max-width:600px){.install-terminal-row{padding:var(--spacing-sm) var(--spacing-md)}.install-terminal-cmd code{font-size:.75rem}}.install-providers{align-items:center;gap:var(--spacing-sm);margin-top:var(--spacing-md);flex-direction:column;display:flex}.install-providers-label{text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.75rem;font-weight:600}.install-providers-row{justify-content:center;gap:var(--spacing-sm);flex-wrap:wrap;display:flex}.install-provider-badge{color:var(--color-charcoal);align-items:center;gap:6px;font-size:.8125rem;display:flex}.install-provider-badge img{border-radius:4px}.install-terminal-cmd--download{align-items:center;gap:var(--spacing-sm);flex-wrap:wrap;display:flex}.prefix-toggle{cursor:pointer;transition:border-color var(--duration-fast) var(--ease-out);background:#0000000f;border:1px solid #00000014;border-radius:6px;align-items:center;gap:8px;padding:6px 12px;display:inline-flex}.prefix-toggle:hover{border-color:#0003}.prefix-toggle input{opacity:0;width:0;height:0;position:absolute}.prefix-toggle-slider{background:var(--color-mist);width:32px;height:18px;transition:background var(--duration-fast) var(--ease-out);border-radius:18px;flex-shrink:0;position:relative}.prefix-toggle-slider:after{content:"";background:var(--color-paper);width:14px;height:14px;transition:transform var(--duration-fast) var(--ease-out);border-radius:50%;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #00000026}.prefix-toggle input:checked+.prefix-toggle-slider{background:var(--color-accent)}.prefix-toggle input:checked+.prefix-toggle-slider:after{transform:translate(14px)}.prefix-toggle input:focus-visible+.prefix-toggle-slider{outline:2px solid var(--color-accent);outline-offset:2px}.prefix-toggle-label{color:var(--color-charcoal);white-space:nowrap;font-size:.75rem}.prefix-toggle-label code{font-family:var(--font-mono);background:var(--color-accent-dim);color:var(--color-accent);border-radius:3px;padding:1px 4px;font-size:.6875rem}.download-tip{color:var(--color-ash);margin-top:var(--spacing-sm);text-align:center;font-size:.8125rem}.download-tip a{color:var(--color-accent);text-decoration:none}.download-tip a:hover{text-decoration:underline}.consulting-section{padding:var(--spacing-xl) 0;border-top:1px solid var(--color-mist)}.consulting-content{justify-content:space-between;align-items:center;gap:var(--spacing-lg);flex-wrap:wrap;display:flex}.consulting-actions{gap:var(--spacing-sm);flex-shrink:0;display:flex}.consulting-text{flex:1;min-width:280px}.consulting-title{margin:0 0 var(--spacing-sm) 0;font-size:clamp(1.5rem,4vw,2rem);font-style:italic;font-weight:300}.consulting-desc{color:var(--color-charcoal);max-width:45ch;margin:0;font-size:1rem;line-height:1.6}@media (max-width:600px){.consulting-content{flex-direction:column;align-items:flex-start}.consulting-actions{flex-direction:column;width:100%}.consulting-actions .btn{justify-content:center;width:100%}} \ No newline at end of file +.split-container:before{content:"";background-image:linear-gradient(var(--color-mist) 1px, transparent 1px), linear-gradient(90deg, var(--color-mist) 1px, transparent 1px);opacity:.3;pointer-events:none;background-size:20px 20px;position:absolute;inset:0}.split-container:after{content:"← Drag →";letter-spacing:.1em;text-transform:uppercase;color:var(--color-ash);background:var(--color-paper);opacity:.8;z-index:10;border-radius:4px;padding:4px 12px;font-size:.625rem;font-weight:600;transition:opacity .3s;position:absolute;bottom:12px;left:50%;transform:translate(-50%)}.split-container:hover:after{opacity:0}.split-after .impeccable-card{box-shadow:0 10px 40px #00000014}@keyframes splitEntry{0%{opacity:0;transform:translate(-50%)skew(-10deg)scaleY(.8)}to{opacity:1;transform:translate(-50%)skew(-10deg)scaleY(1)}}.split-divider{animation:splitEntry .6s var(--ease-out) .3s backwards}.split-label-item{transition:color var(--duration-fast) var(--ease-out);cursor:default}.split-label-item:hover{color:var(--color-text)}.split-label-item[data-point=after]:hover .split-label-dot--accent{transform:scale(1.3)}.split-label-dot{transition:transform var(--duration-fast) var(--ease-spring)}.split-badge{letter-spacing:.08em;text-transform:uppercase;z-index:5;pointer-events:none;border-radius:3px;padding:3px 8px;font-size:.625rem;font-weight:600;position:absolute;top:10px}.split-badge--before{color:var(--color-ash);background:var(--color-paper);border:1px solid var(--color-mist);left:10px}.split-badge--after{color:var(--color-paper);background:var(--color-accent);right:10px}@media (hover:none){.split-container:after{content:"← Swipe →"}}@media (max-width:600px){.split-label{padding:4px 10px;font-size:.5625rem}}.commands-section{padding:var(--spacing-xl) 0;background:var(--color-paper);position:relative}.commands-gallery{display:block}.commands-container{gap:var(--spacing-2xl);grid-template-columns:1fr 1.2fr;align-items:start;display:grid}@media (max-width:900px){.commands-container{grid-template-columns:1fr}}.command-manual{gap:var(--spacing-sm);flex-direction:column;padding-bottom:20vh;display:flex}.command-category-header{font-family:var(--font-display);color:var(--color-accent);text-transform:uppercase;letter-spacing:.1em;padding:var(--spacing-lg) var(--spacing-lg) var(--spacing-sm);margin-top:var(--spacing-md);border-bottom:1px solid var(--color-mist);font-size:.875rem;font-weight:600}.command-category-header:first-child{margin-top:0}.manual-entry{padding:var(--spacing-lg);padding-left:calc(var(--spacing-lg) + 16px);border-left:2px solid var(--color-mist);transition:border-color .4s var(--ease-out), opacity .4s var(--ease-out), background .4s var(--ease-out), transform .4s var(--ease-out);opacity:.4;cursor:pointer;position:relative;transform:translate(-16px)}.manual-entry:hover{opacity:.7}.manual-entry.active{border-left-color:var(--color-accent);opacity:1;background:linear-gradient(to right, var(--color-bg), transparent);transform:translate(0)}.manual-cmd-name{font-family:var(--font-mono);margin:0 0 var(--spacing-sm);color:var(--color-ink);font-size:1.5rem;font-weight:500}.beta-badge{font-family:var(--font-body);letter-spacing:.08em;text-transform:uppercase;color:var(--color-accent);border:1px solid var(--color-accent);vertical-align:middle;border-radius:3px;margin-left:6px;padding:1px 5px;font-size:.55rem;font-weight:600}.manual-cmd-desc{color:var(--color-charcoal);margin:0;font-size:1rem;line-height:1.6}.manual-cmd-rel{color:var(--color-ash);margin-top:var(--spacing-sm);flex-wrap:wrap;align-items:center;gap:.5ch;font-size:.8125rem;display:flex}.manual-cmd-rel .rel-icon{color:var(--color-accent);font-weight:600}.manual-cmd-rel code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 6px;font-size:.75rem}.glass-terminal-wrapper{top:var(--spacing-xl);height:calc(100vh - var(--spacing-xl) * 2);min-height:500px;max-height:800px;position:sticky}.terminal-stack{perspective:1200px;height:100%;position:relative}.terminal-stack-tabs{z-index:10;gap:4px;display:flex;position:absolute;top:-31px;right:8px}.terminal-stack-tab{font-family:var(--font-mono);background:var(--color-cream);border:1px solid var(--color-mist);color:var(--color-ash);cursor:pointer;border-bottom:none;border-radius:6px 6px 0 0;padding:5px 12px;font-size:.75rem;transition:all .2s}.terminal-stack-tab:hover{background:var(--color-paper);color:var(--color-charcoal)}.terminal-stack-tab.active{background:var(--color-paper);color:var(--color-ink);border-color:var(--color-mist)}.terminal-window{transform-origin:bottom;transition:transform .4s cubic-bezier(.4,0,.2,1),opacity .3s,filter .3s;position:absolute;inset:0}.terminal-window--demo{z-index:2}.terminal-window--demo.is-back{opacity:.6;filter:brightness(.92);pointer-events:none;z-index:1;transform:translateY(16px)translate(12px)scale(.96)}.terminal-window--source{z-index:1;opacity:.6;filter:brightness(.92);pointer-events:none;transform:translateY(16px)translate(12px)scale(.96)}.terminal-window--source.is-front{opacity:1;filter:brightness();pointer-events:auto;z-index:2;transform:translateY(0)translate(0)scale(1)}.source-window{background:var(--color-paper);-webkit-backdrop-filter:blur(12px);border:1px solid var(--color-mist);border-radius:8px;flex-direction:column;height:100%;display:flex;overflow:hidden;box-shadow:0 20px 60px -10px #00000026}.source-header{background:var(--color-cream);border-bottom:1px solid var(--color-mist);flex-shrink:0;align-items:center;gap:8px;padding:12px 16px;display:flex}.source-title{font-family:var(--font-mono);color:var(--color-ink);font-size:.875rem;font-weight:500}.source-body{padding:var(--spacing-md);font-family:var(--font-mono);color:var(--color-charcoal);overscroll-behavior:contain;white-space:pre-wrap;word-break:break-word;background:var(--color-cream);flex:1;font-size:.75rem;line-height:1.5;overflow-y:auto}.source-loading{color:var(--color-ash);font-style:italic}@media (max-width:900px){.glass-terminal-wrapper{display:none}}.glass-terminal{background:var(--color-paper);-webkit-backdrop-filter:blur(12px);border:1px solid var(--color-mist);border-radius:8px;flex-direction:column;height:100%;display:flex;overflow:hidden;box-shadow:0 20px 60px -10px #00000026}.terminal-header{background:var(--color-cream);border-bottom:1px solid var(--color-mist);align-items:center;gap:8px;padding:12px 16px;display:flex}.terminal-dot{border-radius:50%;width:10px;height:10px}.terminal-dot.red{background:#ff5f56}.terminal-dot.yellow{background:#ffbd2e}.terminal-dot.green{background:#27c93f}.terminal-title{font-family:var(--font-mono);color:var(--color-ash);margin-left:auto;font-size:.75rem}.terminal-body{padding:var(--spacing-md);font-family:var(--font-mono);color:var(--color-ink);flex-direction:column;flex:1;min-height:0;font-size:.9375rem;display:flex;overflow-y:auto}.terminal-line{margin-bottom:var(--spacing-sm);gap:var(--spacing-sm);line-height:1.5;display:flex}.terminal-prompt{color:var(--color-accent);-webkit-user-select:none;user-select:none;font-weight:700}.terminal-cursor{background:var(--color-accent);vertical-align:middle;width:8px;height:1.2em;animation:1s step-end infinite blink;display:inline-block}.terminal-output{color:var(--color-ash);margin-bottom:var(--spacing-md);white-space:pre-wrap}@media (max-height:800px){.terminal-output{display:none}}.terminal-cmd{color:var(--color-accent);font-weight:600}.terminal-step{color:var(--color-charcoal)}.terminal-done{color:var(--color-success,#22c55e);font-weight:500}.terminal-preview{background:var(--color-paper);margin:var(--spacing-sm) 0;border-radius:12px;flex:1;min-height:0;overflow:hidden}.terminal-cursor-line{flex-shrink:0;margin-top:var(--spacing-sm)!important}.terminal-preview .demo-split-comparison{flex-direction:column;height:100%;display:flex}.terminal-preview .demo-split-comparison .split-container{cursor:ew-resize;-webkit-user-select:none;user-select:none;background:var(--color-cream);flex:1;min-height:0;position:relative;overflow:hidden}.terminal-preview .demo-split-comparison .split-before,.terminal-preview .demo-split-comparison .split-after{padding:var(--spacing-md);justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.terminal-preview .demo-split-comparison .split-before{z-index:1;background:var(--color-cream)}.terminal-preview .demo-split-comparison .split-after{z-index:2;background:var(--color-paper);clip-path:polygon(58% 0%,100% 0%,100% 100%,42% 100%)}.terminal-preview .demo-split-comparison .split-content{flex-direction:column;justify-content:center;align-items:center;width:100%;max-width:280px;display:flex}.terminal-preview .demo-split-comparison .split-divider{background:var(--color-accent);pointer-events:none;z-index:3;width:2px;position:absolute;top:0;bottom:0;left:50%;transform:translate(-50%)skew(-10deg);box-shadow:0 0 12px #0000001a}.terminal-preview .demo-split-comparison .split-label{letter-spacing:.08em;text-transform:uppercase;color:var(--color-paper);background:var(--color-accent);white-space:nowrap;border-radius:3px;padding:4px 10px;font-size:.5625rem;font-weight:600;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)skew(10deg)}.terminal-preview .demo-split-comparison .demo-caption{color:var(--color-ash);text-align:center;padding:var(--spacing-sm) var(--spacing-md);flex-shrink:0;font-size:.75rem}@keyframes blink{50%{opacity:0}}.casestudies-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist);position:relative}.transformations-tabbed{margin-top:var(--spacing-xl)}.transformation-tabs{gap:var(--spacing-xs);border-bottom:1px solid var(--color-mist);margin-bottom:var(--spacing-lg);display:flex}.transformation-tab{font-family:var(--font-display);color:var(--color-ash);padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;background:0 0;border:none;font-size:.9375rem;font-weight:500;transition:color .2s;position:relative}.transformation-tab:hover{color:var(--color-charcoal)}.transformation-tab.active{color:var(--color-ink)}.transformation-tab.active:after{content:"";background:var(--color-accent);height:2px;position:absolute;bottom:-1px;left:0;right:0}.transformation-panels{position:relative}.transformation-panel{gap:var(--spacing-lg);flex-direction:column;animation:.3s fadeInPanel;display:none}.transformation-panel.active{display:flex}@keyframes fadeInPanel{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.transformation-images{align-items:center;gap:var(--spacing-md);display:flex}.transformation-before,.transformation-after{flex:1;margin:0}.transformation-before img,.transformation-after img,.transformation-placeholder{aspect-ratio:16/10;object-fit:cover;border:1px solid var(--color-mist);cursor:pointer;border-radius:8px;width:100%;transition:transform .2s,box-shadow .2s}.transformation-before img:hover,.transformation-after img:hover,.transformation-placeholder:hover{transform:scale(1.02);box-shadow:0 8px 24px -4px #00000026}.transformation-placeholder{background:linear-gradient(135deg, var(--color-mist) 0%, var(--color-cream) 100%);color:var(--color-ash);justify-content:center;align-items:center;font-size:.8125rem;font-style:italic;display:flex}.transformation-before figcaption,.transformation-after figcaption{text-transform:uppercase;letter-spacing:.05em;color:var(--color-ash);margin-top:var(--spacing-xs);text-align:center;font-size:.75rem;font-weight:600}.transformation-arrow{color:var(--color-accent);flex-shrink:0;font-size:1.5rem;font-weight:300}.transformation-info{max-width:600px}.transformation-title{font-family:var(--font-display);color:var(--color-ink);margin:0 0 var(--spacing-xs);font-size:1.25rem;font-weight:600}.transformation-desc{color:var(--color-charcoal);margin:0 0 var(--spacing-sm);font-size:.9375rem;line-height:1.6}.transformation-commands{flex-wrap:wrap;gap:6px;display:flex}.transformation-command{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-charcoal);border-radius:4px;padding:4px 10px;font-size:.75rem}.lightbox{z-index:1000;opacity:0;visibility:hidden;background:#000000e6;justify-content:center;align-items:center;transition:opacity .3s,visibility .3s;display:flex;position:fixed;inset:0}.lightbox.active{opacity:1;visibility:visible}.lightbox-close{color:#fff;cursor:pointer;opacity:.7;background:0 0;border:none;font-size:2.5rem;line-height:1;transition:opacity .2s;position:absolute;top:20px;right:24px}.lightbox-close:hover{opacity:1}.lightbox-image{object-fit:contain;border-radius:8px;max-width:90vw;max-height:85vh;box-shadow:0 20px 60px #00000080}@media (max-width:768px){.transformation-images{flex-direction:column}.transformation-arrow{transform:rotate(90deg)}.transformation-before,.transformation-after{width:100%}}.hero-version-link{color:var(--color-ash);margin-top:var(--spacing-sm);font-size:.8125rem}.hero-version-link a{color:var(--color-ash);border-bottom:1px solid #0000;text-decoration:none;transition:color .2s,border-color .2s}.hero-version-link a:hover{color:var(--color-accent);border-bottom-color:var(--color-accent)}.changelog-section{padding:var(--spacing-xl) 0;border-top:1px solid var(--color-mist);position:relative}.changelog-list{flex-direction:column;gap:0;display:flex}.changelog-entry{padding:var(--spacing-md) 0;border-bottom:1px solid var(--color-mist)}.changelog-entry:first-child{border-top:1px solid var(--color-mist)}.changelog-version-header{align-items:baseline;gap:var(--spacing-sm);margin-bottom:var(--spacing-sm);display:flex}.changelog-version{font-family:var(--font-mono);color:var(--color-ink);font-size:1.125rem;font-weight:600}.changelog-date{color:var(--color-ash);font-size:.8125rem}.changelog-items{padding-left:var(--spacing-md);color:var(--color-charcoal);margin:0;line-height:1.7}.changelog-items li{margin-bottom:var(--spacing-xs)}.changelog-items code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 6px;font-size:.875em}.faq-section{padding:var(--spacing-xl) 0;border-top:1px solid var(--color-mist);position:relative}.faq-list{flex-direction:column;gap:0;display:flex}.faq-item{border-bottom:1px solid var(--color-mist)}.faq-item:first-child{border-top:1px solid var(--color-mist)}.faq-question{font-family:var(--font-display);color:var(--color-ink);padding:var(--spacing-md) 0;cursor:pointer;justify-content:space-between;align-items:center;font-size:1.125rem;font-weight:500;list-style:none;transition:color .2s;display:flex}.faq-question::-webkit-details-marker{display:none}.faq-question:after{content:"+";font-family:var(--font-body);color:var(--color-accent);transition:transform .3s var(--ease-out);font-size:1.5rem;font-weight:300}.faq-item[open] .faq-question:after{transform:rotate(45deg)}.faq-question:hover{color:var(--color-accent)}.faq-answer{padding:0 0 var(--spacing-md);color:var(--color-charcoal);animation:faqFadeIn .3s var(--ease-out);line-height:1.7}.faq-answer p{margin:0 0 var(--spacing-sm)}.faq-answer p:last-child{margin-bottom:0}.faq-answer ul{margin:var(--spacing-sm) 0;padding-left:var(--spacing-md)}.faq-answer li{margin-bottom:var(--spacing-xs)}.faq-answer code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 6px;font-size:.875em}.faq-answer a{color:var(--color-accent);border-bottom:1px solid #0000;text-decoration:none;transition:border-color .2s}.faq-answer a:hover{border-bottom-color:var(--color-accent)}@keyframes faqFadeIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.skills-section{padding:var(--spacing-xl) 0;background:var(--color-bg);position:relative;overflow:hidden}.skills-gallery{display:block;position:relative}.gallery-track{gap:var(--spacing-lg);scroll-snap-type:x mandatory;padding:var(--spacing-md) var(--spacing-lg) var(--spacing-xl);-webkit-overflow-scrolling:touch;scrollbar-width:none;cursor:grab;display:flex;overflow-x:auto}.gallery-track:active{cursor:grabbing}.gallery-track::-webkit-scrollbar{display:none}.gallery-frame{scroll-snap-align:center;background:var(--color-paper);border:1px solid var(--color-mist);opacity:.4;max-width:1100px;transition:opacity .6s var(--ease-out), transform .6s var(--ease-out), box-shadow .6s var(--ease-out);border-radius:2px;flex:0 0 80vw;position:relative;overflow:hidden;transform:scale(.95);box-shadow:0 4px 6px -1px #0000000d,0 20px 50px -10px #0000001a}.gallery-frame.active{opacity:1;border-color:var(--color-charcoal);border-width:1px;transform:scale(1);box-shadow:0 20px 25px -5px #0000001a,0 40px 100px -20px #0003}.gallery-content{grid-template-columns:1.2fr 1fr;height:600px;display:grid}@media (max-width:900px){.gallery-frame{flex:0 0 90vw}.gallery-content{grid-template-columns:1fr;height:auto;min-height:600px}}.gallery-visual{background:var(--color-cream);border-right:1px solid var(--color-mist);padding:var(--spacing-lg);justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden}.gallery-info{padding:var(--spacing-xl);flex-direction:column;display:flex;overflow-y:auto}.gallery-header{margin-bottom:var(--spacing-lg)}.gallery-title{font-family:var(--font-display);margin:0 0 var(--spacing-xs);color:var(--color-ink);font-size:2.5rem;font-style:italic}.gallery-meta{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.75rem}.gallery-desc{color:var(--color-charcoal);margin-bottom:var(--spacing-xl);max-width:45ch;font-size:1.125rem;line-height:1.6}.gallery-tags{gap:var(--spacing-xs);flex-wrap:wrap;margin-top:auto;display:flex}.gallery-tag{border:1px solid var(--color-mist);color:var(--color-ash);border-radius:4px;padding:6px 12px;font-size:.8125rem}.gallery-map{margin-top:var(--spacing-lg);justify-content:center;gap:8px;display:flex}.gallery-dot{background:var(--color-mist);cursor:pointer;width:40px;height:2px;font:inherit;border:none;padding:0;transition:all .3s;position:relative}.gallery-dot:after{content:"";position:absolute;inset:-10px 0}.gallery-dot:focus-visible{outline:2px solid var(--color-accent);outline-offset:4px;border-radius:1px}.gallery-dot.active{background:var(--color-accent);height:4px}.demo-tabbed-container{flex-direction:column;display:flex}.demo-tabs{background:var(--color-paper);border-bottom:1px solid var(--color-mist);justify-content:center;gap:0;margin-bottom:0;display:flex}.demo-tab{padding:var(--spacing-sm) var(--spacing-lg);font-family:var(--font-mono);letter-spacing:.05em;text-transform:uppercase;color:var(--color-ash);cursor:pointer;transition:all var(--duration-fast) var(--ease-out);background:0 0;border:none;border-bottom:2px solid #0000;font-size:.75rem;font-weight:500}.demo-tab:hover{color:var(--color-text);background:var(--color-cream)}.demo-tab.active{color:var(--color-accent);border-bottom-color:var(--color-accent);background:var(--color-accent-dim)}.demo-panels{flex:1}.demo-panel{display:none}.demo-panel.active{animation:fadeSlideIn .3s var(--ease-out);display:block}@keyframes fadeSlideIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.demo-container{background:var(--color-paper);border:none;border-radius:0;overflow:hidden}.demo-header{padding:var(--spacing-sm) var(--spacing-md);background:var(--color-paper);border-bottom:1px solid var(--color-mist);justify-content:center;align-items:center;min-height:48px;display:flex}.demo-toggle{align-items:center;gap:var(--spacing-md);display:flex}.demo-toggle-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.08em;color:var(--color-ash);transition:color var(--duration-fast) var(--ease-out);cursor:pointer;font-size:.6875rem;font-weight:600}.demo-toggle-label:hover{color:var(--color-text)}.demo-toggle-label.active{color:var(--color-accent)}.demo-toggle-switch{background:var(--color-mist);cursor:pointer;width:44px;height:24px;transition:background var(--duration-fast) var(--ease-out);font:inherit;border:1px solid #0000;border-radius:12px;padding:0;position:relative}.demo-toggle-switch:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}.demo-toggle-switch:hover{border-color:var(--color-ash)}.demo-toggle-switch:after{content:"";background:var(--color-paper);width:16px;height:16px;transition:transform var(--duration-base) var(--ease-spring);border-radius:50%;position:absolute;top:3px;left:3px;box-shadow:0 1px 4px #00000026}.demo-toggle-switch.active{background:var(--color-accent)}.demo-toggle-switch.active:after{transform:translate(20px)}.demo-viewport{padding:var(--spacing-xl);background:var(--color-cream);min-height:280px;transition:background var(--duration-base) var(--ease-out);justify-content:center;align-items:center;display:flex}.demo-viewport[data-state=after]{background:var(--color-paper)}.demo-caption{padding:var(--spacing-sm) var(--spacing-md);font-family:var(--font-mono);letter-spacing:.03em;color:var(--color-ash);background:var(--color-paper);text-align:center;font-size:.6875rem}.uxw-demo{width:100%;max-width:320px;padding:var(--spacing-lg);background:var(--color-paper);border:1px solid var(--color-mist);text-align:center;border-radius:6px}.uxw-error-icon{margin-bottom:var(--spacing-sm);font-size:2rem}.uxw-error-title{color:#c00;margin-bottom:var(--spacing-xs);font-weight:600}.uxw-error-text{color:var(--color-ash);font-size:.875rem}.uxw-error-action{margin-top:var(--spacing-sm);color:var(--color-accent);cursor:pointer;font-size:.875rem;text-decoration:underline}.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)}.uxw-button-context{color:var(--color-charcoal);margin-bottom:var(--spacing-md);font-size:.875rem;font-weight:500}.uxw-button-row{gap:var(--spacing-sm);justify-content:center;display:flex}.uxw-btn{padding:var(--spacing-xs) var(--spacing-md);cursor:pointer;border:none;border-radius:4px;font-size:.875rem;font-weight:500}.uxw-btn-primary{background:var(--color-text);color:var(--color-paper)}.uxw-btn-secondary{color:var(--color-ash);border:1px solid var(--color-mist);background:0 0}.uxw-btn-danger{color:#fff;background:#c00}.uxw-empty-icon{margin-bottom:var(--spacing-sm);opacity:.4;font-size:2.5rem}.uxw-empty-title{color:var(--color-ash);font-weight:500}.uxw-empty-text{color:var(--color-charcoal);margin-top:var(--spacing-xs);font-size:.875rem}.uxw-empty-action{margin-top:var(--spacing-md)}.uxw-empty-after .uxw-empty-icon{opacity:1}.uxw-empty-after .uxw-empty-title{color:var(--color-text)}.spatial-demo{width:100%;max-width:340px;padding:var(--spacing-md);background:var(--color-paper);border:1px solid var(--color-mist);border-radius:6px}.spatial-grid-before{flex-wrap:wrap;gap:6px;display:flex}.spatial-grid-after{gap:var(--spacing-sm);grid-template-columns:1fr 1fr;display:grid}.spatial-card-item{padding:var(--spacing-sm);background:var(--color-bg);border:1px solid var(--color-mist);color:var(--color-charcoal);text-align:center;border-radius:4px;font-size:.8125rem}.spatial-grid-after .spatial-card-item{width:auto!important}.spatial-hierarchy-before .spatial-h-title,.spatial-hierarchy-before .spatial-h-subtitle,.spatial-hierarchy-before .spatial-h-cta,.spatial-hierarchy-before .spatial-h-link{margin-bottom:var(--spacing-xs);color:var(--color-charcoal);font-size:.9375rem}.spatial-hierarchy-after .spatial-h-title{font-family:var(--font-display);margin-bottom:var(--spacing-xs);color:var(--color-text);font-size:1.75rem;font-style:italic;font-weight:300}.spatial-hierarchy-after .spatial-h-subtitle{text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);margin-bottom:var(--spacing-md);font-size:.6875rem}.spatial-hierarchy-after .spatial-h-cta{padding:var(--spacing-sm) var(--spacing-lg);background:var(--color-text);color:var(--color-paper);margin-bottom:var(--spacing-sm);border-radius:4px;font-size:.875rem;font-weight:500;display:inline-block}.spatial-hierarchy-after .spatial-h-link{color:var(--color-ash);font-size:.75rem}.spatial-whitespace-before{padding:var(--spacing-xs)!important}.spatial-whitespace-before .spatial-ws-title{margin-bottom:2px;font-size:1rem;font-weight:600}.spatial-whitespace-before .spatial-ws-price{color:var(--color-ash);margin-bottom:4px;font-size:.875rem}.spatial-whitespace-before .spatial-ws-features{color:var(--color-ash);margin-bottom:6px;font-size:.75rem}.spatial-whitespace-before .spatial-ws-btn{background:var(--color-text);width:100%;color:var(--color-paper);cursor:pointer;border:none;border-radius:3px;padding:6px;font-size:.75rem}.spatial-whitespace-after{padding:var(--spacing-lg)!important}.spatial-whitespace-after .spatial-ws-title{font-family:var(--font-display);margin-bottom:var(--spacing-sm);font-size:1.5rem;font-weight:400}.spatial-whitespace-after .spatial-ws-price{color:var(--color-text);margin-bottom:var(--spacing-sm);font-size:1.25rem;font-weight:600}.spatial-whitespace-after .spatial-ws-features{color:var(--color-ash);margin-bottom:var(--spacing-lg);font-size:.8125rem;line-height:1.6}.spatial-whitespace-after .spatial-ws-btn{width:100%;padding:var(--spacing-sm);background:var(--color-text);color:var(--color-paper);cursor:pointer;border:none;border-radius:4px;font-size:.875rem;font-weight:500}.motion-demo{align-items:center;gap:var(--spacing-sm);flex-direction:column;width:100%;max-width:280px;display:flex}.motion-stagger-demo{align-items:stretch}.motion-list-item{align-items:center;gap:var(--spacing-sm);padding:var(--spacing-sm) var(--spacing-md);background:var(--color-bg);border:1px solid var(--color-mist);color:var(--color-charcoal);border-radius:4px;font-size:.875rem;display:flex}.motion-dot{background:var(--color-accent);border-radius:50%;width:8px;height:8px}.demo-viewport[data-state=after] .motion-list-item{opacity:0;animation:.35s cubic-bezier(.16,1,.3,1) forwards staggerIn;transform:translateY(12px)}.demo-viewport[data-state=after] .motion-list-item:first-child{animation-delay:0s}.demo-viewport[data-state=after] .motion-list-item:nth-child(2){animation-delay:50ms}.demo-viewport[data-state=after] .motion-list-item:nth-child(3){animation-delay:.1s}.demo-viewport[data-state=after] .motion-list-item:nth-child(4){animation-delay:.15s}@keyframes staggerIn{to{opacity:1;transform:translateY(0)}}.motion-btn{cursor:pointer;border:none;border-radius:4px;padding:12px 24px;font-size:.9375rem;font-weight:500}.motion-btn-before{background:var(--color-charcoal);color:var(--color-paper)}.motion-btn-after{background:var(--color-text);color:var(--color-paper);transition:transform .2s cubic-bezier(.34,1.56,.64,1),box-shadow .2s}.motion-btn-after:hover{transform:translateY(-2px);box-shadow:0 4px 12px #00000026}.motion-btn-after:active{transform:translateY(0)scale(.98)}.motion-card{padding:var(--spacing-md);background:var(--color-bg);border:1px solid var(--color-mist);text-align:center;border-radius:6px;min-width:140px}.motion-card-icon{margin-bottom:var(--spacing-xs);font-size:1.5rem}.motion-card-text{color:var(--color-charcoal);font-size:.8125rem}.motion-card-after{transition:all .3s cubic-bezier(.34,1.56,.64,1)}.demo-viewport[data-state=after] .motion-card-after{background:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.demo-viewport[data-state=after] .motion-card-after{background:color-mix(in oklch, var(--color-accent) 10%, var(--color-paper))}}.demo-viewport[data-state=after] .motion-card-after{border-color:var(--color-accent)}.demo-viewport[data-state=after] .motion-card-after .motion-card-icon{animation:.4s cubic-bezier(.34,1.56,.64,1) checkPop}@keyframes checkPop{50%{transform:scale(1.3)}}.typo-demo{text-align:left;width:100%;max-width:320px}.typo-pairing-before{font-family:Inter,system-ui,sans-serif}.typo-pairing-before .typo-heading{margin-bottom:var(--spacing-xs);font-size:1.5rem;font-weight:600}.typo-pairing-before .typo-body{color:var(--color-ash);font-size:.9375rem;line-height:1.5}.typo-pairing-after .typo-heading{font-family:var(--font-display);letter-spacing:-.02em;margin-bottom:var(--spacing-sm);color:var(--color-text);font-size:2rem;font-style:italic;font-weight:300}.typo-pairing-after .typo-body{font-family:var(--font-body);color:var(--color-charcoal);font-size:.9375rem;line-height:1.7}.typo-hierarchy-before .typo-h1{margin-bottom:4px;font-size:1.125rem;font-weight:600}.typo-hierarchy-before .typo-meta{color:var(--color-ash);margin-bottom:var(--spacing-xs);font-size:.9375rem}.typo-hierarchy-before .typo-p{color:var(--color-charcoal);font-size:.875rem;line-height:1.5}.typo-hierarchy-after .typo-h1{font-family:var(--font-display);letter-spacing:-.03em;margin-bottom:2px;font-size:2.25rem;font-weight:300;line-height:1.1}.typo-hierarchy-after .typo-meta{text-transform:uppercase;letter-spacing:.12em;color:var(--color-accent);margin-bottom:var(--spacing-md);font-size:.6875rem}.typo-hierarchy-after .typo-p{color:var(--color-ash);font-size:.9375rem;line-height:1.7}.int-demo{gap:var(--spacing-md);flex-direction:column;width:100%;max-width:280px;display:flex}.int-states-demo{gap:var(--spacing-lg)}.int-state-row{align-items:center;gap:var(--spacing-md);display:flex}.int-state-label{text-transform:uppercase;letter-spacing:.08em;color:var(--color-ash);width:40px;font-size:.6875rem}.int-btn{padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;border-radius:4px;flex:1;font-size:.875rem;font-weight:500}.int-btn-poor{background:var(--color-charcoal);color:var(--color-paper);border:none}.int-btn-good{background:var(--color-text);color:var(--color-paper);border:2px solid #0000;transition:all .15s}.int-btn-good:hover{background:var(--color-charcoal)}.int-btn-good:focus{border-color:var(--color-accent);box-shadow:0 0 0 3px var(--color-accent);outline:none}@supports (color:color-mix(in lab, red, red)){.int-btn-good:focus{box-shadow:0 0 0 3px color-mix(in oklch, var(--color-accent) 25%, transparent)}}.int-btn-good:active{transform:scale(.98)}.int-aff-item{padding:var(--spacing-sm) var(--spacing-md);cursor:pointer;border-radius:4px;font-size:.875rem}.int-aff-poor{color:var(--color-charcoal)}.int-aff-good{color:var(--color-accent);text-underline-offset:2px;text-decoration:underline}.int-aff-good:after{content:" →"}.int-affordance-after .int-aff-item{background:var(--color-bg);border:1px solid var(--color-mist);color:var(--color-accent);text-underline-offset:2px;text-decoration:underline;transition:background .15s}.int-affordance-after .int-aff-item:hover{background:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.int-affordance-after .int-aff-item:hover{background:color-mix(in oklch, var(--color-accent) 5%, var(--color-paper))}}.int-affordance-after .int-aff-item:after{content:" →"}.int-feedback-before,.int-feedback-after{align-items:center;gap:var(--spacing-md);flex-direction:row;display:flex}.int-fb-btn{cursor:pointer;border:none;border-radius:50%;justify-content:center;align-items:center;width:48px;height:48px;display:flex}.int-fb-btn svg{width:22px;height:22px}.int-fb-silent{background:var(--color-mist);color:var(--color-ash)}.int-fb-active{background:var(--color-charcoal);color:var(--color-paper);transition:all .15s cubic-bezier(.34,1.56,.64,1)}.int-fb-active:hover{transform:scale(1.1)}.int-fb-active:active{transform:scale(.95)}.int-fb-active.liked{background:var(--color-accent);animation:.35s cubic-bezier(.34,1.56,.64,1) heartPop}@keyframes heartPop{50%{transform:scale(1.25)}}.int-fb-label{color:var(--color-charcoal);font-size:.875rem}.color-demo{width:100%;max-width:300px}.color-palette-before,.color-palette-after{gap:var(--spacing-xs);padding:var(--spacing-md);background:var(--color-paper);border:1px solid var(--color-mist);border-radius:6px;flex-wrap:wrap;display:flex}.color-swatch{border-radius:4px;width:40px;height:40px;transition:background .2s}.color-card{width:100%;margin-top:var(--spacing-sm);padding:var(--spacing-sm);background:var(--color-paper);border:1px solid var(--color-mist);border-radius:4px;flex-direction:column;gap:4px;display:flex}.color-card span{font-size:.8125rem;font-weight:500;transition:color .2s}.color-card button{cursor:pointer;border:none;border-radius:3px;padding:6px;font-size:.75rem;font-weight:500;transition:all .2s}.color-palette-before .swatch-1{background:#ff6b6b}.color-palette-before .swatch-2{background:#4ecdc4}.color-palette-before .swatch-3{background:#ffe66d}.color-palette-before .swatch-4{background:#95e1d3}.color-palette-before .swatch-5{background:#f38181}.color-palette-before .card-title{color:#ff6b6b}.color-palette-before .card-subtitle{color:#4ecdc4}.color-palette-before .card-btn{color:#333;background:#ffe66d}.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)}.color-accent-card{padding:var(--spacing-md);border-radius:6px}.color-accent-before .color-accent-card{background:#f5f5f5;border:1px solid #e0e0e0}.color-accent-before .color-accent-title{color:#333;margin-bottom:4px;font-weight:600}.color-accent-before .color-accent-text{color:#666;margin-bottom:var(--spacing-sm);font-size:.8125rem}.color-accent-before .color-accent-btn{width:100%;padding:var(--spacing-xs);color:#fff;cursor:pointer;background:#333;border:none;border-radius:4px;font-size:.8125rem}.color-accent-after .color-accent-card{background:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.color-accent-after .color-accent-card{background:color-mix(in oklch, var(--color-accent) 8%, var(--color-paper))}}.color-accent-after .color-accent-card{border:1px solid var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.color-accent-after .color-accent-card{border:1px solid color-mix(in oklch, var(--color-accent) 20%, var(--color-paper))}}.color-accent-after .color-accent-title{color:var(--color-text);margin-bottom:4px;font-weight:600}.color-accent-after .color-accent-text{color:var(--color-ash);margin-bottom:var(--spacing-sm);font-size:.8125rem}.color-accent-after .color-accent-btn{width:100%;padding:var(--spacing-xs);background:var(--color-accent);color:var(--color-paper);cursor:pointer;border:none;border-radius:4px;font-size:.8125rem;font-weight:500}.color-contrast-static{gap:var(--spacing-sm);flex-direction:column;display:flex}.contrast-example{padding:var(--spacing-md);text-align:center;border-radius:6px}.contrast-fail{color:#a0a0a0;background:#f0f0f0}.contrast-pass{background:var(--color-charcoal);color:var(--color-paper)}.contrast-badge{text-transform:uppercase;letter-spacing:.1em;border-radius:2px;margin-bottom:4px;padding:2px 6px;font-size:.5625rem;font-weight:600;display:inline-block}.contrast-fail .contrast-badge{background:#ddd}.contrast-pass .contrast-badge{background:var(--color-accent);color:var(--color-paper)}.contrast-text{margin-bottom:2px;font-size:1rem;font-weight:500}.contrast-ratio{opacity:.7;font-size:.6875rem}.resp-demo{width:100%;max-width:340px}.resp-touch-demo{gap:var(--spacing-lg);flex-direction:column;display:flex}.resp-touch-row{align-items:center;gap:var(--spacing-md);display:flex}.resp-label{text-transform:uppercase;letter-spacing:.08em;color:var(--color-ash);width:70px;font-size:.6875rem}.resp-touch-targets{gap:4px;display:flex}.resp-touch-targets button{cursor:pointer;border:none;border-radius:4px;font-weight:500}.resp-touch-bad button{background:var(--color-mist);width:24px;height:24px;color:var(--color-ash);font-size:.75rem}.resp-touch-good button{background:var(--color-text);width:44px;height:44px;color:var(--color-paper);font-size:1rem}.resp-fluid-demo{padding:var(--spacing-md);background:var(--color-bg);border:1px solid var(--color-mist);border-radius:6px}.resp-fluid-container{gap:var(--spacing-md);flex-direction:column;display:flex}.resp-fluid-fixed,.resp-fluid-adaptive{color:var(--color-ash);font-size:.75rem}.resp-fluid-fixed span,.resp-fluid-adaptive span{margin-bottom:4px;display:block}.resp-fluid-bar{background:var(--color-mist);border-radius:4px;height:24px}.resp-fluid-adaptive .resp-fluid-bar{background:var(--color-accent)}.resp-adapt-demo{gap:var(--spacing-sm);align-items:flex-end;display:flex}.resp-device{text-align:center}.resp-device>span{color:var(--color-ash);text-transform:uppercase;letter-spacing:.08em;margin-top:4px;font-size:.625rem;display:block}.resp-device-screen{background:var(--color-paper);border:2px solid var(--color-mist);border-radius:4px;flex-direction:column;gap:3px;padding:4px;display:flex}.resp-device-mobile .resp-device-screen{width:50px;height:80px}.resp-device-tablet .resp-device-screen{width:80px;height:60px}.resp-device-desktop .resp-device-screen{width:120px;height:70px}.resp-block{background:var(--color-mist);border-radius:2px}.resp-block-row{flex:1;gap:3px;display:flex}.resp-header{background:var(--color-charcoal);height:16px}.resp-sidebar{background:var(--color-charcoal);width:30%}.resp-content{flex:1}@keyframes fadeIn{to{opacity:1}}@media (prefers-reduced-motion:reduce){*,:before,:after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}*,:before,:after{box-sizing:border-box}*{margin:0}img,picture,video,canvas,svg{max-width:100%;display:block}button,input,textarea,select{font:inherit}:root{--font-display:"Cormorant Garamond", Georgia, serif;--font-body:"Instrument Sans", system-ui, sans-serif;--font-mono:"Space Grotesk", monospace;--spacing-xs:8px;--spacing-sm:16px;--spacing-md:24px;--spacing-lg:32px;--spacing-xl:48px;--spacing-2xl:80px;--spacing-3xl:120px;--width-max:1400px;--width-content:900px;--ease-out:cubic-bezier(.16, 1, .3, 1);--ease-in-out:cubic-bezier(.65, 0, .35, 1);--ease-spring:cubic-bezier(.34, 1.56, .64, 1);--duration-fast:.15s;--duration-base:.3s;--duration-slow:.6s;--duration-slower:.8s;--duration-slowest:1.2s;--color-ink:oklch(10% 0 0);--color-text:oklch(10% 0 0);--color-paper:oklch(98% 0 0);--color-cream:oklch(96% .005 350);--color-charcoal:oklch(25% 0 0);--color-ash:oklch(55% 0 0);--color-mist:oklch(92% 0 0);--color-bg:oklch(96% .005 350);--color-accent:oklch(60% .25 350);--color-accent-hover:oklch(52% .25 350);--color-accent-dim:oklch(60% .25 350/.15);--color-accent-soft:oklch(60% .25 350/.25);--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}.skip-link{z-index:10000;padding:var(--spacing-sm) var(--spacing-lg);background:var(--color-ink);color:var(--color-paper);border-radius:0 0 8px 8px;font-weight:600;text-decoration:none;transition:top .2s;position:absolute;top:-100%;left:50%;transform:translate(-50%)}.skip-link:focus{outline:2px solid var(--color-accent);outline-offset:2px;top:0}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizelegibility;overflow-x:clip}body{font-family:var(--font-body);color:var(--color-text);background:var(--color-paper);min-height:100dvh;font-size:16px;line-height:1.625;overflow-x:clip}h1,h2,h3,h4,h5,h6{font-family:var(--font-display);letter-spacing:-.02em;color:var(--color-ink);font-weight:400;line-height:1.1}a{color:var(--color-accent);text-underline-offset:2px;transition:color var(--duration-fast) var(--ease-out), text-decoration-color var(--duration-fast) var(--ease-out);text-decoration:underline;text-decoration-thickness:1px}a:hover{color:var(--color-accent-hover);text-decoration-thickness:2px}.btn,.footer-logo,[class*=nav-item]{text-decoration:none}strong{color:var(--color-ink);font-weight:600}code{font-family:var(--font-mono);background:var(--color-accent-dim);color:var(--color-accent);border-radius:4px;padding:.15em .4em;font-size:.9em}::selection{background:var(--color-accent-soft);color:var(--color-ink)}.grain-overlay{pointer-events:none;z-index:9999;opacity:.03;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");background-repeat:repeat;position:fixed;inset:0}.site-content{max-width:var(--width-max);padding:0 var(--spacing-lg);margin:0 auto}@media (max-width:768px){.site-content{padding:0 var(--spacing-md)}}.section-header{margin-bottom:var(--spacing-lg);position:relative}.section-number{font-family:var(--font-mono);letter-spacing:.05em;color:var(--color-ash);margin-bottom:var(--spacing-xs);text-transform:uppercase;font-size:.625rem;font-weight:500;display:block}.section-title{margin:0;font-size:clamp(1.75rem,4vw,2.5rem);font-weight:400;line-height:1.2}.section-subtitle{color:var(--color-charcoal);margin-top:var(--spacing-sm);max-width:55ch;font-size:1rem;line-height:1.6}.cheatsheet-link{color:var(--color-accent);margin-left:.5em;font-size:.875rem;text-decoration:none}.cheatsheet-link:hover{text-decoration:underline}.section-lead{color:var(--color-charcoal);max-width:55ch;margin-bottom:var(--spacing-lg);font-size:1rem;line-height:1.6}.hero-combined{min-height:100dvh;padding:var(--spacing-2xl) 0;background:var(--color-paper);flex-direction:column;justify-content:center;display:flex;position:relative}.github-link{top:var(--spacing-md);right:var(--spacing-lg);z-index:10;color:var(--color-ash);transition:color .2s;position:absolute}.github-link:hover{color:var(--color-ink)}.github-link svg{width:28px;height:28px}.hero-combined-container{max-width:var(--width-max);padding:0 var(--spacing-lg);gap:var(--spacing-xl);grid-template-columns:1fr 1fr;align-items:center;width:100%;margin:0 auto;display:grid}@media (max-width:1024px){.hero-combined-container{gap:var(--spacing-lg);text-align:center;grid-template-columns:1fr}}.hero-combined-left{gap:var(--spacing-md);flex-direction:column;display:flex}@media (max-width:1024px){.hero-combined-left{align-items:center}}.hero-title-combined{font-family:var(--font-display);letter-spacing:-.02em;color:var(--color-ink);margin:0;font-size:clamp(2.5rem,7vw,4.5rem);font-style:italic;font-weight:300;line-height:1}.hero-tagline-combined{font-family:var(--font-display);color:var(--color-charcoal);margin:0;font-size:clamp(1.125rem,2.5vw,1.75rem);font-style:italic;font-weight:400;line-height:1.3}.hero-hook-text{color:var(--color-charcoal);max-width:45ch;margin:0;font-size:1rem;line-height:1.6}.hero-included-box{border:1px solid var(--color-mist);background:0 0;flex-direction:column;gap:6px;max-width:45ch;padding:10px 14px;display:flex}.hero-included-title{font-family:var(--font-body);text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.5625rem;font-weight:500}.hero-included-items{color:var(--color-charcoal);flex-wrap:wrap;align-items:center;gap:6px;font-size:.8125rem;line-height:1.5;display:flex}.hero-included-items em{font-style:normal;font-family:var(--font-mono);font-size:.75rem}.hero-included-sep{color:var(--color-mist)}@media (max-width:500px){.hero-included-items{flex-direction:column;align-items:flex-start;gap:4px}.hero-included-sep{display:none}}.hero-cta-group{align-items:center;gap:var(--spacing-lg);margin-top:var(--spacing-sm);display:flex}@media (max-width:600px){.hero-cta-group{gap:var(--spacing-md);flex-direction:column}}.hero-cta-combined{padding:var(--spacing-sm) var(--spacing-xl);font-family:var(--font-body);letter-spacing:.05em;text-transform:uppercase;color:var(--color-paper);background:var(--color-ink);border:none;font-size:.9rem;font-weight:500;text-decoration:none;transition:transform .2s,background .2s;display:inline-block}.hero-cta-combined:hover{background:var(--color-accent);color:var(--color-paper);transform:translateY(-2px)}.hero-logos-inline{align-items:center;gap:var(--spacing-sm);display:flex}.hero-logos-inline .hero-logos-label{color:var(--color-ash);letter-spacing:.03em;font-size:.6875rem}.hero-logos-inline .hero-logos-row{align-items:center;gap:8px;display:flex}.hero-logos-inline .hero-logos-row img{opacity:.7;border-radius:4px;transition:opacity .2s}.hero-logos-inline .hero-logos-row img:hover{opacity:1}.hero-combined-right{justify-content:center;display:flex}.hero-combined-right .split-comparison{width:100%;max-width:520px}.hero-combined-right .split-container{max-width:100%}.hero-bias-tags{align-items:center;gap:var(--spacing-xs);margin-top:var(--spacing-lg);padding-top:var(--spacing-md);border-top:1px solid var(--color-mist);max-width:var(--width-max);width:100%;padding-bottom:var(--spacing-md);flex-direction:column;margin-left:auto;margin-right:auto;display:flex}.problem-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.problem-content{gap:var(--spacing-xl);display:grid}.split-comparison{width:100%;max-width:600px;margin:-20px auto;padding:20px;position:relative}.split-container{background:var(--color-cream);border:1px solid var(--color-mist);cursor:ew-resize;-webkit-user-select:none;user-select:none;border-radius:12px;width:100%;max-width:500px;height:380px;margin:0 auto;position:relative;overflow:hidden}.split-before,.split-after{justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.split-before{z-index:1}.split-content{justify-content:center;align-items:center;width:100%;height:100%;display:flex}.split-after{clip-path:polygon(78% 0%,100% 0%,100% 100%,62% 100%);z-index:2;background:var(--color-paper)}.split-divider{background:var(--color-accent);pointer-events:none;z-index:3;width:3px;position:absolute;top:0;bottom:0;left:70%;transform:translate(-50%)skew(-10deg);box-shadow:0 0 20px #00000026}.split-label{letter-spacing:.08em;text-transform:uppercase;color:var(--color-paper);background:var(--color-accent);white-space:nowrap;border-radius:4px;padding:6px 14px;font-size:.6875rem;font-weight:600;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)skew(10deg);box-shadow:0 2px 8px #0003}.slop-card{background:linear-gradient(135deg,#f5f3ff 0%,#ede9fe 50%,#ddd6fe 100%);border-radius:16px;flex-direction:column;width:280px;height:280px;padding:24px;font-family:Inter,system-ui,sans-serif;display:flex;box-shadow:0 4px 6px -1px #0000001a}.slop-header{align-items:center;gap:12px;margin-bottom:16px;display:flex}.slop-avatar{background:linear-gradient(135deg,#8b5cf6,#7c3aed);border-radius:50%;flex-shrink:0;width:40px;height:40px}.slop-text{flex:1}.slop-title{color:#1f2937;margin-bottom:2px;font-size:14px;font-weight:600}.slop-subtitle{color:#6b7280;font-size:12px}.slop-body{color:#4b5563;flex:1;margin-bottom:auto;font-size:13px;line-height:1.5}.slop-button{color:#fff;cursor:pointer;background:linear-gradient(135deg,#8b5cf6,#7c3aed);border:none;border-radius:8px;width:100%;margin-top:auto;padding:10px 20px;font-family:Inter,system-ui,sans-serif;font-size:13px;font-weight:500}.slop-callouts{pointer-events:none;position:absolute;inset:0}.slop-callout{text-transform:uppercase;letter-spacing:.06em;color:var(--color-accent);background:var(--color-paper);border:1px solid var(--color-accent);white-space:nowrap;opacity:0;animation:calloutFadeIn .4s var(--ease-out) forwards;border-radius:3px;padding:4px 8px;font-size:.625rem;font-weight:600;position:absolute;box-shadow:0 2px 8px #0000001a}.slop-callout[data-point=font]{animation-delay:.1s;top:15%;right:5%}.slop-callout[data-point=gradient]{animation-delay:.25s;top:40%;left:5%}.slop-callout[data-point=copy]{animation-delay:.4s;bottom:35%;right:8%}.slop-callout[data-point=rounded]{animation-delay:.55s;bottom:12%;left:10%}@keyframes calloutFadeIn{0%{opacity:0;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.impeccable-card{background:var(--color-paper);border:1px solid var(--color-mist);width:280px;height:300px;padding:var(--spacing-lg);text-align:left;flex-direction:column;display:flex}.impeccable-eyebrow{font-family:var(--font-mono);letter-spacing:.15em;text-transform:uppercase;color:var(--color-accent);margin-bottom:var(--spacing-xs);font-size:.625rem;font-weight:500}.impeccable-title{font-family:var(--font-display);color:var(--color-ink);margin-bottom:var(--spacing-sm);font-size:1.75rem;font-style:italic;font-weight:300;line-height:1.1}.impeccable-body{color:var(--color-ash);flex:1;margin-bottom:auto;font-size:.875rem;line-height:1.6}.impeccable-button{margin-top:var(--spacing-sm);background:var(--color-ink);color:var(--color-paper);font-family:var(--font-body);letter-spacing:.03em;cursor:pointer;transition:all var(--duration-base) var(--ease-out);border:none;align-self:flex-start;padding:.625rem 1.5rem;font-size:.8125rem;font-weight:500;display:inline-flex}.impeccable-button:hover{background:var(--color-accent)}.split-labels{justify-content:center;gap:var(--spacing-xl);margin-top:var(--spacing-md);display:flex}.split-label-item{align-items:center;gap:var(--spacing-xs);color:var(--color-ash);font-size:.8125rem;display:flex}.split-label-dot{background:var(--color-mist);border-radius:50%;width:8px;height:8px}.split-label-dot--accent{background:var(--color-accent)}.solution-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.solution-content{gap:var(--spacing-lg);display:grid}.solution-content .section-lead{margin-bottom:0}.solution-visual{gap:var(--spacing-lg);grid-template-columns:1fr auto 1fr;align-items:stretch;display:grid}@media (max-width:900px){.solution-visual{gap:var(--spacing-md);grid-template-columns:1fr}}.solution-visual-interactive{background:var(--color-paper);border:1px solid var(--color-mist);border-radius:8px;width:100%;min-height:380px;position:relative;overflow:hidden}.solution-pillar{background:var(--color-cream);border:1px solid var(--color-mist);padding:var(--spacing-lg);transition:all var(--duration-base) var(--ease-out)}.solution-pillar:hover{border-color:var(--color-accent);box-shadow:0 20px 60px var(--color-accent-dim);transform:translateY(-4px)}.pillar-header{text-align:center;margin-bottom:var(--spacing-lg);padding-bottom:var(--spacing-md);border-bottom:1px solid var(--color-mist)}.pillar-icon{background:var(--color-accent-dim);width:56px;height:56px;color:var(--color-accent);margin-bottom:var(--spacing-sm);border-radius:50%;justify-content:center;align-items:center;display:inline-flex}.pillar-title{font-family:var(--font-display);margin:0 0 var(--spacing-xs);font-size:1.75rem;font-weight:400}.pillar-subtitle{color:var(--color-ash);margin:0;font-size:.875rem}.pillar-content{gap:var(--spacing-sm);flex-direction:column;display:flex}.pillar-item{padding:var(--spacing-sm);background:var(--color-paper);transition:all var(--duration-fast) var(--ease-out);border-radius:4px;justify-content:space-between;align-items:center;display:flex}.pillar-item:hover{background:var(--color-accent-dim)}.pillar-item-name{color:var(--color-ink);font-size:.9375rem;font-weight:500}.pillar-item-code{font-family:var(--font-mono);color:var(--color-accent);background:0 0;padding:0;font-size:.875rem;font-weight:500}.pillar-item-desc{color:var(--color-ash);font-size:.75rem}.pillar-item--more{color:var(--color-accent);border:1px dashed var(--color-mist);background:0 0;justify-content:center;font-size:.8125rem;font-weight:500}.solution-connector{justify-content:center;align-items:center;display:flex}.connector-plus{font-family:var(--font-display);color:var(--color-accent);opacity:.5;font-size:3rem;font-weight:300}@media (max-width:900px){.solution-connector{padding:var(--spacing-sm) 0}.connector-plus{font-size:2rem}}.skills-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.skills-gallery{gap:var(--spacing-xl);grid-template-columns:200px 1fr;align-items:start;display:grid}@media (max-width:968px){.skills-gallery{gap:var(--spacing-lg);grid-template-columns:1fr}}.skills-nav{top:var(--spacing-lg);flex-direction:column;gap:2px;display:flex;position:sticky}@media (max-width:968px){.skills-nav{gap:var(--spacing-xs);flex-flow:wrap;position:static}}.skill-nav-item{padding:var(--spacing-sm) var(--spacing-md);color:var(--color-ash);font-family:var(--font-body);cursor:pointer;text-align:left;background:0 0;border:none;border-left:2px solid #0000;font-size:.9375rem;font-weight:400;text-decoration:none;transition:all .2s;display:block}.skill-nav-item:hover{color:var(--color-text);background:var(--color-cream)}.skill-nav-item.active{color:var(--color-accent);border-left-color:var(--color-accent);background:var(--color-accent-dim);font-weight:500}@media (max-width:968px){.skill-nav-item{padding:var(--spacing-xs) var(--spacing-md);border-bottom:2px solid #0000;border-left:none}.skill-nav-item.active{border-bottom-color:var(--color-accent)}}.skills-showcase{gap:var(--spacing-lg);grid-template-columns:1.2fr 1fr;align-items:start;display:grid}@media (max-width:1100px){.skills-showcase{grid-template-columns:1fr}}.loading-state{padding:var(--spacing-xl);text-align:center;color:var(--color-ash);font-style:italic}.mobile-commands-layout{display:none}@media (max-width:900px){.mobile-commands-layout{gap:var(--spacing-md);flex-direction:column;display:flex}.commands-container{display:none}}.mobile-carousel-wrapper{-webkit-overflow-scrolling:touch;scrollbar-width:none;padding:var(--spacing-xs) 0;overflow-x:auto}.mobile-carousel-wrapper::-webkit-scrollbar{display:none}.mobile-carousel{gap:var(--spacing-xs);padding-right:var(--spacing-md);display:flex}.mobile-cmd-pill{padding:var(--spacing-sm) var(--spacing-md);min-height:44px;font-family:var(--font-mono);color:var(--color-ash);background:var(--color-cream);border:1px solid var(--color-mist);cursor:pointer;white-space:nowrap;border-radius:100px;flex-shrink:0;font-size:.8125rem;font-weight:500;transition:all .2s}.mobile-cmd-pill:hover{color:var(--color-charcoal);border-color:var(--color-charcoal)}.mobile-cmd-pill.active{color:var(--color-paper);background:var(--color-ink);border-color:var(--color-ink)}.mobile-demo-area{background:var(--color-cream);border:1px solid var(--color-mist);padding:var(--spacing-sm);border-radius:8px}.mobile-demo-area .demo-split-comparison{width:100%}.mobile-demo-area .split-container{width:100%;max-width:100%;height:320px}.mobile-demo-area .demo-caption{margin-top:var(--spacing-sm);font-size:.75rem}.mobile-info-area{padding-top:var(--spacing-sm)}.mobile-cmd-info{padding:var(--spacing-sm) 0;display:none}.mobile-cmd-info.active{display:block}.mobile-cmd-name{font-family:var(--font-mono);color:var(--color-ink);margin:0 0 var(--spacing-xs) 0;font-size:1.125rem;font-weight:600}.mobile-cmd-desc{color:var(--color-charcoal);margin:0;font-size:.875rem;line-height:1.5}.mobile-cmd-rel{margin-top:var(--spacing-xs);color:var(--color-ash);font-size:.75rem}.mobile-cmd-rel code{font-family:var(--font-mono);color:var(--color-ink)}.downloads-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.downloads-grid{gap:var(--spacing-lg);grid-template-columns:repeat(auto-fit,minmax(280px,1fr));display:grid}.download-card{text-align:center;padding:var(--spacing-lg);background:var(--color-cream);border:1px solid var(--color-mist);transition:all var(--duration-base) var(--ease-out);flex-direction:column;align-items:center;display:flex}.download-card:hover{border-color:var(--color-accent);box-shadow:0 20px 60px var(--color-accent-dim);transform:translateY(-4px)}.download-card-icon{margin-bottom:var(--spacing-sm)}.download-card-icon img{object-fit:contain;border-radius:8px;width:40px;height:40px}.download-card-title{font-family:var(--font-display);margin:0 0 var(--spacing-sm) 0;font-size:1.25rem;font-weight:400}.download-card-note{color:var(--color-ash);margin-bottom:var(--spacing-xs);font-size:.75rem}.download-card .btn{margin-top:var(--spacing-xs)}.install-command{align-items:center;gap:var(--spacing-xs);background:var(--color-paper);border:1px solid var(--color-mist);padding:var(--spacing-sm);margin-top:var(--spacing-sm);border-radius:6px;width:100%;display:flex}.install-command code{font-family:var(--font-mono);color:var(--color-ink);white-space:nowrap;text-overflow:ellipsis;background:0 0;flex:1;padding:0;font-size:.75rem;overflow:hidden}.copy-btn{border:1px solid var(--color-mist);width:28px;height:28px;color:var(--color-ash);cursor:pointer;transition:all var(--duration-fast) var(--ease-out);background:0 0;border-radius:4px;flex-shrink:0;justify-content:center;align-items:center;display:flex}.copy-btn:hover{background:var(--color-accent-dim);border-color:var(--color-accent);color:var(--color-accent)}.copy-btn.copied{background:var(--color-accent);border-color:var(--color-accent);color:var(--color-paper)}.install-hint{color:var(--color-ash);margin:var(--spacing-xs) 0 0 0;font-size:.75rem}.install-hint code{font-family:var(--font-mono);background:var(--color-mist);border-radius:3px;padding:2px 5px;font-size:.6875rem}.download-card-details{width:100%;margin-top:var(--spacing-sm);text-align:left;font-size:.8125rem}.download-card-details summary{cursor:pointer;color:var(--color-ash);padding:var(--spacing-xs) 0;justify-content:center;align-items:center;gap:4px;font-size:.75rem;list-style:none;display:flex}.download-card-details summary:before{content:"▶";transition:transform var(--duration-fast) var(--ease-out);font-size:.5rem}.download-card-details[open] summary:before{transform:rotate(90deg)}.download-card-details summary::-webkit-details-marker{display:none}.download-card-details ol{margin:var(--spacing-sm) 0;padding-left:var(--spacing-md);color:var(--color-charcoal);line-height:1.6}.download-card-details li{margin-bottom:4px}.download-card-details code{font-family:var(--font-mono);background:var(--color-mist);border-radius:3px;padding:2px 5px;font-size:.6875rem}.download-card-details a{color:var(--color-accent);font-size:.75rem;text-decoration:none}.download-card-details a:hover{text-decoration:underline}.opensource-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist);text-align:center}.opensource-content{align-items:center;gap:var(--spacing-md);flex-direction:column;max-width:500px;margin:0 auto;display:flex}.opensource-title{font-size:clamp(1.5rem,4vw,2rem);font-weight:300}.opensource-desc{color:var(--color-ash);font-size:1.125rem;line-height:1.6}.site-footer{border-top:1px solid var(--color-mist);padding:var(--spacing-xl) var(--spacing-lg);background:var(--color-cream)}.footer-content{max-width:var(--width-max);justify-content:space-between;align-items:center;gap:var(--spacing-lg);flex-wrap:wrap;margin:0 auto;display:flex}@media (max-width:768px){.footer-content{text-align:center;flex-direction:column}}.footer-brand{gap:var(--spacing-xs);flex-direction:column;display:flex}.footer-logo{font-family:var(--font-display);color:var(--color-ink);font-size:1.25rem;font-weight:400}.footer-tagline{color:var(--color-ash);font-size:.875rem}.footer-links{gap:var(--spacing-lg);flex-wrap:wrap;display:flex}.footer-links a{color:var(--color-ash);transition:color var(--duration-fast) var(--ease-out);font-size:.875rem}.footer-links a:hover{color:var(--color-accent)}.footer-author{justify-content:center;align-items:center;gap:var(--spacing-md);width:100%;padding-top:var(--spacing-lg);margin-top:var(--spacing-md);border-top:1px solid var(--color-mist);flex-wrap:wrap;display:flex}.footer-author-label{color:var(--color-ash);font-size:.875rem}.footer-author-label a{color:var(--color-text);transition:color var(--duration-fast) var(--ease-out)}.footer-author-label a:hover{color:var(--color-accent)}.footer-author-links{align-items:center;gap:var(--spacing-sm);display:flex}.footer-social-link{width:36px;height:36px;color:var(--color-ash);transition:all var(--duration-fast) var(--ease-out);background:0 0;border-radius:50%;justify-content:center;align-items:center;text-decoration:none;display:flex}.footer-social-link:hover{color:var(--color-accent);background:var(--color-accent-dim)}.footer-author-divider{background:var(--color-mist);width:1px;height:20px;margin:0 var(--spacing-xs)}.footer-newsletter{color:var(--color-text);background:var(--color-paper);border:1px solid var(--color-mist);transition:all var(--duration-fast) var(--ease-out);border-radius:100px;align-items:center;gap:6px;padding:8px 14px;font-size:.875rem;font-weight:500;text-decoration:none;display:inline-flex}.footer-newsletter:hover{border-color:var(--color-accent);color:var(--color-accent)}.footer-newsletter svg{transition:transform var(--duration-fast) var(--ease-out)}.footer-newsletter:hover svg{transform:translate(3px)}@media (max-width:768px){.footer-author{gap:var(--spacing-sm);flex-direction:column}.footer-author-divider{display:none}}.btn{justify-content:center;align-items:center;gap:var(--spacing-xs);font-family:var(--font-body);letter-spacing:.03em;cursor:pointer;transition:all var(--duration-base) var(--ease-out);border:none;padding:1rem 2rem;font-size:.9375rem;font-weight:600;text-decoration:none;display:inline-flex;position:relative;overflow:hidden}.btn-primary{background:var(--color-ink);color:var(--color-paper)}.btn-primary:before{content:"";background:var(--color-accent);transition:transform var(--duration-base) var(--ease-out);z-index:0;position:absolute;inset:0;transform:translateY(100%)}.btn-primary:hover:before{transform:translateY(0)}.btn-primary:hover{color:var(--color-paper)}.btn-primary span,.btn-primary svg,.btn-primary:not(:has(span)){z-index:1;position:relative}.btn-secondary{color:var(--color-ink);border:1px solid var(--color-ink);background:0 0}.btn-secondary:hover{background:var(--color-ink);color:var(--color-paper)}.btn:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px}.btn-primary:focus-visible{outline-color:var(--color-paper);box-shadow:0 0 0 4px var(--color-accent)}.btn-secondary:focus-visible{outline-color:var(--color-accent)}@keyframes revealUp{to{opacity:1;transform:translateY(0)}}@keyframes float{0%,to{transform:translate(-50%)translateY(0)}50%{transform:translate(-50%)translateY(-8px)}}@keyframes bounce{0%,to{transform:translateY(0)}50%{transform:translateY(4px)}}[data-reveal]{opacity:0;transition:opacity .8s var(--ease-out), transform .8s var(--ease-out);transform:translateY(30px)}[data-reveal].revealed{opacity:1;transform:translateY(0)}[data-reveal]:first-child{transition-delay:0s}[data-reveal]:nth-child(2){transition-delay:.1s}[data-reveal]:nth-child(3){transition-delay:.2s}[data-reveal]:nth-child(4){transition-delay:.3s}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}html{scroll-behavior:auto}.hero-canvas{display:none}.hero-scroll-indicator{opacity:1;animation:none}[data-reveal],.gallery-frame{opacity:1;transform:none}}.load-error{text-align:center;padding:var(--spacing-2xl) var(--spacing-lg);justify-content:center;align-items:center;gap:var(--spacing-md);background:var(--color-cream);border:1px solid var(--color-mist);border-radius:8px;flex-direction:column;display:flex}.load-error-icon{color:var(--color-accent);font-size:2.5rem}.load-error-title{font-family:var(--font-display);color:var(--color-ink);margin:0;font-size:1.5rem;font-weight:400}.load-error-text{color:var(--color-ash);max-width:40ch;font-size:1rem;line-height:1.5}.load-error-retry{margin-top:var(--spacing-sm)}.bias-tags{align-items:center;gap:var(--spacing-sm);margin-top:var(--spacing-lg);flex-direction:column;display:flex}.bias-tags-label{font-family:var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--color-ash);font-size:.6875rem;font-weight:500}.bias-tags-list{justify-content:center;gap:var(--spacing-xs);flex-wrap:wrap;display:flex}.bias-tag{background:var(--color-cream);border:1px solid var(--color-mist);color:var(--color-charcoal);transition:all var(--duration-fast) var(--ease-out);padding:6px 12px;font-size:.75rem;font-weight:500}.bias-tag:hover{border-color:var(--color-accent);color:var(--color-accent)}.antidote-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.patterns-categories{margin-bottom:var(--spacing-xl)}.pattern-tabs{gap:var(--spacing-xs);margin-bottom:var(--spacing-lg);flex-wrap:wrap;display:flex}.pattern-tab{font-family:var(--font-body);color:var(--color-ash);padding:var(--spacing-xs) var(--spacing-sm);cursor:pointer;transition:color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out);background:0 0;border:none;border-bottom:2px solid #0000;font-size:.875rem}.pattern-tab:hover{color:var(--color-charcoal)}.pattern-tab.active{color:var(--color-ink);border-bottom-color:var(--color-accent);font-weight:500}.pattern-tab:focus-visible{outline:2px solid var(--color-accent);outline-offset:2px;border-radius:4px}.pattern-panel{display:none}.pattern-panel.active{display:block}.pattern-columns{gap:var(--spacing-xl);grid-template-columns:1fr 1fr;display:grid}@media (max-width:768px){.pattern-columns{gap:var(--spacing-md);grid-template-columns:1fr}}.pattern-column-label{text-transform:uppercase;letter-spacing:.1em;margin-bottom:var(--spacing-sm);color:var(--color-ash);font-size:.6875rem;font-weight:600;display:block}.pattern-column--anti .pattern-column-label{color:var(--color-accent)}.pattern-column--do .pattern-column-label{color:var(--color-success,#22c55e)}.pattern-list{gap:var(--spacing-xs);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.pattern-item{padding-left:var(--spacing-md);font-size:.8125rem;line-height:1.5;position:relative}.pattern-item--anti{color:var(--color-ash)}.pattern-item--anti:before{content:"×";color:var(--color-accent);font-weight:600;position:absolute;left:0}.pattern-item--do{color:var(--color-charcoal)}.pattern-item--do:before{content:"✓";color:var(--color-success,#22c55e);font-weight:600;position:absolute;left:0}.contribute-inline{color:var(--color-ash);margin-top:var(--spacing-md);font-size:.875rem}.contribute-inline a{color:var(--color-accent);text-decoration:none}.contribute-inline a:hover{text-decoration:underline}.pillar-item--main{background:var(--color-accent-dim);border:1px solid var(--color-accent)}.pillar-item--main .pillar-item-name{color:var(--color-accent);font-size:1.125rem;font-weight:600}.pillar-item--ref{padding:var(--spacing-xs) var(--spacing-sm);background:0 0}.pillar-item-label{text-transform:uppercase;letter-spacing:.05em;color:var(--color-ash);font-size:.75rem;font-weight:500}.pillar-refs{gap:var(--spacing-xs);padding:0 var(--spacing-sm);flex-wrap:wrap;display:flex}.pillar-ref{text-transform:uppercase;letter-spacing:.03em;background:var(--color-paper);color:var(--color-ash);border:1px solid var(--color-mist);transition:all var(--duration-fast) var(--ease-out);border-radius:3px;padding:4px 10px;font-size:.6875rem;font-weight:500}.pillar-ref:hover{border-color:var(--color-accent);color:var(--color-accent)}.pillar-command-group{align-items:center;gap:var(--spacing-xs);padding:var(--spacing-sm);background:var(--color-paper);border-radius:4px;flex-wrap:wrap;display:flex}.pillar-group-label{text-transform:uppercase;letter-spacing:.05em;color:var(--color-ash);width:100%;margin-bottom:4px;font-size:.6875rem;font-weight:600}.pillar-command-group .pillar-item-code{background:var(--color-accent-dim);border-radius:3px;padding:4px 8px;font-size:.8125rem}.platforms-section{padding:var(--spacing-2xl) 0;border-top:1px solid var(--color-mist)}.platforms-section .section-subtitle{max-width:60ch}.install-terminal{max-width:640px;margin:0 auto var(--spacing-xl)}.install-terminal .glass-terminal{height:auto}.install-terminal .terminal-body{flex-direction:column;padding:0;display:flex}.install-terminal-row{padding:var(--spacing-md) var(--spacing-lg);flex-direction:column;gap:6px;display:flex}.install-terminal-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.625rem;font-weight:600}.install-terminal-cmd{align-items:center;gap:var(--spacing-sm);display:flex}.install-terminal-cmd .terminal-prompt{flex-shrink:0}.install-terminal-cmd code{font-family:var(--font-mono);color:var(--color-ink);white-space:nowrap;text-overflow:ellipsis;background:0 0;flex:1;padding:0;font-size:.9375rem;overflow:hidden}.install-terminal-cmd .copy-btn{flex-shrink:0}.install-terminal-cmd .btn{padding:.5rem 1rem;font-size:.8125rem}.install-terminal-note{color:var(--color-ash);padding-left:calc(.75rem + var(--spacing-sm));font-size:.75rem}.install-terminal-note code{font-family:var(--font-mono);background:var(--color-mist);color:var(--color-ink);border-radius:3px;padding:2px 5px;font-size:.6875rem}.install-terminal-divider{background:var(--color-mist);height:1px;margin:0}@media (max-width:600px){.install-terminal-row{padding:var(--spacing-sm) var(--spacing-md)}.install-terminal-cmd code{font-size:.75rem}}.install-providers{align-items:center;gap:var(--spacing-sm);margin-top:var(--spacing-md);flex-direction:column;display:flex}.install-providers-label{text-transform:uppercase;letter-spacing:.1em;color:var(--color-ash);font-size:.75rem;font-weight:600}.install-providers-row{justify-content:center;gap:var(--spacing-sm);flex-wrap:wrap;display:flex}.install-provider-badge{color:var(--color-charcoal);align-items:center;gap:6px;font-size:.8125rem;display:flex}.install-provider-badge img{border-radius:4px}.install-terminal-cmd--download{align-items:center;gap:var(--spacing-sm);flex-wrap:wrap;display:flex}.prefix-toggle{cursor:pointer;transition:border-color var(--duration-fast) var(--ease-out);background:#0000000f;border:1px solid #00000014;border-radius:6px;align-items:center;gap:8px;padding:6px 12px;display:inline-flex}.prefix-toggle:hover{border-color:#0003}.prefix-toggle input{opacity:0;width:0;height:0;position:absolute}.prefix-toggle-slider{background:var(--color-mist);width:32px;height:18px;transition:background var(--duration-fast) var(--ease-out);border-radius:18px;flex-shrink:0;position:relative}.prefix-toggle-slider:after{content:"";background:var(--color-paper);width:14px;height:14px;transition:transform var(--duration-fast) var(--ease-out);border-radius:50%;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #00000026}.prefix-toggle input:checked+.prefix-toggle-slider{background:var(--color-accent)}.prefix-toggle input:checked+.prefix-toggle-slider:after{transform:translate(14px)}.prefix-toggle input:focus-visible+.prefix-toggle-slider{outline:2px solid var(--color-accent);outline-offset:2px}.prefix-toggle-label{color:var(--color-charcoal);white-space:nowrap;font-size:.75rem}.prefix-toggle-label code{font-family:var(--font-mono);background:var(--color-accent-dim);color:var(--color-accent);border-radius:3px;padding:1px 4px;font-size:.6875rem}.download-tip{color:var(--color-ash);margin-top:var(--spacing-sm);text-align:center;font-size:.8125rem}.download-tip a{color:var(--color-accent);text-decoration:none}.download-tip a:hover{text-decoration:underline}.consulting-section{padding:var(--spacing-xl) 0;border-top:1px solid var(--color-mist)}.consulting-content{justify-content:space-between;align-items:center;gap:var(--spacing-lg);flex-wrap:wrap;display:flex}.consulting-actions{gap:var(--spacing-sm);flex-shrink:0;display:flex}.consulting-text{flex:1;min-width:280px}.consulting-title{margin:0 0 var(--spacing-sm) 0;font-size:clamp(1.5rem,4vw,2rem);font-style:italic;font-weight:300}.consulting-desc{color:var(--color-charcoal);max-width:45ch;margin:0;font-size:1rem;line-height:1.6}@media (max-width:600px){.consulting-content{flex-direction:column;align-items:flex-start}.consulting-actions{flex-direction:column;width:100%}.consulting-actions .btn{justify-content:center;width:100%}} \ No newline at end of file diff --git a/public/css/workflow.css b/public/css/workflow.css index ae27d1891..c78a7db14 100644 --- a/public/css/workflow.css +++ b/public/css/workflow.css @@ -78,6 +78,20 @@ font-weight: 500; } +.beta-badge { + font-family: var(--font-body); + font-size: 0.55rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--color-accent); + border: 1px solid var(--color-accent); + border-radius: 3px; + padding: 1px 5px; + vertical-align: middle; + margin-left: 6px; +} + .manual-cmd-desc { font-size: 1rem; line-height: 1.6; diff --git a/public/js/components/framework-viz.js b/public/js/components/framework-viz.js index f2850250d..723cf6f3f 100644 --- a/public/js/components/framework-viz.js +++ b/public/js/components/framework-viz.js @@ -3,7 +3,7 @@ * Clean grid visualization showing all commands organized by category */ -import { commandCategories, commandRelationships } from '../data.js'; +import { commandCategories, commandRelationships, betaCommands } from '../data.js'; // Colors now reference CSS custom properties for dark mode support const categoryColors = { @@ -334,6 +334,24 @@ export class PeriodicTable { name.textContent = `/${cmd}`; el.appendChild(name); + // Beta badge + if (betaCommands.includes(cmd)) { + const badge = document.createElement('div'); + badge.style.cssText = ` + position: absolute; + top: 2px; + right: 3px; + font-family: var(--font-mono); + font-size: 5px; + letter-spacing: 0.05em; + color: ${colors.text}; + opacity: 0.45; + text-transform: uppercase; + `; + badge.textContent = 'β'; + el.appendChild(badge); + } + // Shared handler for activation (hover or focus) const activate = () => { // Visual feedback diff --git a/public/js/components/glass-terminal.js b/public/js/components/glass-terminal.js index 6902c9c20..e9fafd09f 100644 --- a/public/js/components/glass-terminal.js +++ b/public/js/components/glass-terminal.js @@ -1,6 +1,6 @@ import { renderCommandDemo, initCommandDemo } from "../demo-renderer.js"; import { initSplitCompare } from "../effects/split-compare.js"; -import { commandProcessSteps, commandCategories, commandRelationships } from "../data.js"; +import { commandProcessSteps, commandCategories, commandRelationships, betaCommands } from "../data.js"; // Track current split instance and command for cleanup let currentSplitInstance = null; @@ -141,9 +141,11 @@ function renderManualEntry(cmd) { } } + const isBeta = betaCommands.includes(cmd.id); + return `
-

/${cmd.id}

+

/${cmd.id}${isBeta ? ' BETA' : ''}

${cmd.description}

${relationshipHTML}
diff --git a/public/js/data.js b/public/js/data.js index dc1d2de62..60e13859a 100644 --- a/public/js/data.js +++ b/public/js/data.js @@ -12,6 +12,11 @@ export const readyCommands = [ 'normalize' // First command to be fully completed ]; +// Commands marked as beta — shown with a badge in the UI +export const betaCommands = [ + 'overdrive' +]; + // Consolidated frontend-design skill with reference domains export const skillFocusAreas = { 'frontend-design': [ diff --git a/public/js/demos/commands/overdrive.js b/public/js/demos/commands/overdrive.js index 1cff8c91a..2c732db4a 100644 --- a/public/js/demos/commands/overdrive.js +++ b/public/js/demos/commands/overdrive.js @@ -47,116 +47,140 @@ export default { ctx.fillStyle = '#0e0d0b'; ctx.fillRect(0, 0, w, h); - // ── Signature path ── - function buildSignaturePath() { - const pts = []; - function bez(x0,y0, cx1,cy1, cx2,cy2, x1,y1, n) { - for (let i = 0; i <= n; i++) { - const t = i / n, mt = 1-t; - pts.push({ - x: mt*mt*mt*x0 + 3*mt*mt*t*cx1 + 3*mt*t*t*cx2 + t*t*t*x1, - y: mt*mt*mt*y0 + 3*mt*mt*t*cy1 + 3*mt*t*t*cy2 + t*t*t*y1 - }); + // ── Signature paths — two separate strokes ── + function buildSignaturePaths() { + function makePath(buildFn) { + const pts = []; + function bez(x0,y0, cx1,cy1, cx2,cy2, x1,y1, n) { + for (let i = 0; i <= n; i++) { + const t = i / n, mt = 1-t; + pts.push({ + x: mt*mt*mt*x0 + 3*mt*mt*t*cx1 + 3*mt*t*t*cx2 + t*t*t*x1, + y: mt*mt*mt*y0 + 3*mt*mt*t*cy1 + 3*mt*t*t*cy2 + t*t*t*y1 + }); + } } + buildFn(bez); + return pts; } - // P - bez(6,44, 5,32, 4,18, 8,8, 14); - bez(8,8, 16,5, 26,7, 26,16, 12); - bez(26,16, 26,22, 18,26, 14,28, 10); - // a - bez(14,28, 18,22, 23,20, 26,22, 8); - bez(26,22, 29,24, 28,30, 24,32, 6); - bez(24,32, 28,34, 30,30, 32,28, 5); - // u - bez(32,28, 34,36, 38,40, 42,32, 8); - bez(42,32, 44,26, 47,24, 48,28, 6); - // l - bez(48,28, 49,16, 50,6, 53,8, 10); - bez(53,8, 55,14, 56,28, 58,32, 8); - // B - bez(66,44, 66,32, 67,16, 70,8, 14); - bez(70,8, 78,4, 83,10, 79,18, 12); - bez(79,18, 84,15, 87,24, 80,30, 12); - bez(80,30, 78,34, 80,36, 84,32, 5); - // akaus - bez(84,32, 89,24, 94,22, 97,26, 8); - bez(97,26, 99,30, 96,34, 100,30, 5); - bez(100,30, 101,20, 102,14, 104,16, 8); - bez(104,16, 106,24, 109,28, 107,32, 6); - bez(107,32, 105,36, 110,36, 113,30, 6); - bez(113,30, 118,24, 122,22, 125,28, 8); - bez(125,28, 128,36, 133,38, 137,30, 8); - bez(137,30, 139,26, 142,24, 144,28, 5); - bez(144,28, 154,24, 170,22, 195,28, 16); - // Same scaling as the static preview version + const paul = makePath(bez => { + // P + bez(6,44, 5,32, 4,18, 8,8, 14); + bez(8,8, 16,5, 26,7, 26,16, 12); + bez(26,16, 26,22, 18,26, 14,28, 10); + // a + bez(14,28, 18,22, 23,20, 26,22, 8); + bez(26,22, 29,24, 28,30, 24,32, 6); + bez(24,32, 28,34, 30,30, 32,28, 5); + // u + bez(32,28, 34,36, 38,40, 42,32, 8); + bez(42,32, 44,26, 47,24, 48,28, 6); + // l + bez(48,28, 49,16, 50,6, 53,8, 10); + bez(53,8, 55,14, 56,28, 58,32, 8); + }); + + const bakaus = makePath(bez => { + // B + bez(66,44, 66,32, 67,16, 70,8, 14); + bez(70,8, 78,4, 83,10, 79,18, 12); + bez(79,18, 84,15, 87,24, 80,30, 12); + bez(80,30, 78,34, 80,36, 84,32, 5); + // akaus + bez(84,32, 89,24, 94,22, 97,26, 8); + bez(97,26, 99,30, 96,34, 100,30, 5); + bez(100,30, 101,20, 102,14, 104,16, 8); + bez(104,16, 106,24, 109,28, 107,32, 6); + bez(107,32, 105,36, 110,36, 113,30, 6); + bez(113,30, 118,24, 122,22, 125,28, 8); + bez(125,28, 128,36, 133,38, 137,30, 8); + bez(137,30, 139,26, 142,24, 144,28, 5); + bez(144,28, 154,24, 170,22, 195,28, 16); + }); + + // Scale both paths const rawW = 200; const scale = (w * 0.7) / rawW; const ox = (w - rawW * scale) / 2; const oy = h * 0.52; - return pts.map(p => ({ x: p.x * scale + ox, y: p.y * scale * 0.75 + oy })); + const transform = p => ({ x: p.x * scale + ox, y: p.y * scale * 0.75 + oy }); + return [paul.map(transform), bakaus.map(transform)]; } - const sigPoints = buildSignaturePath(); - const segLengths = []; - let totalLength = 0; - for (let i = 1; i < sigPoints.length; i++) { - const dx = sigPoints[i].x - sigPoints[i-1].x; - const dy = sigPoints[i].y - sigPoints[i-1].y; - segLengths.push(Math.sqrt(dx*dx + dy*dy)); - totalLength += segLengths[segLengths.length - 1]; + const strokes = buildSignaturePaths(); + + // Precompute lengths for each stroke + function computeLengths(pts) { + const lens = []; + let total = 0; + for (let i = 1; i < pts.length; i++) { + const dx = pts[i].x - pts[i-1].x, dy = pts[i].y - pts[i-1].y; + const l = Math.sqrt(dx*dx + dy*dy); + lens.push(l); total += l; + } + return { lens, total }; } - function posAt(dist) { + const strokeData = strokes.map(pts => { + const { lens, total } = computeLengths(pts); + return { pts, lens, total }; + }); + + function posAtStroke(stroke, dist) { let d = 0; - for (let i = 0; i < segLengths.length; i++) { - if (d + segLengths[i] >= dist) { - const t = segLengths[i] > 0 ? (dist - d) / segLengths[i] : 0; - const p0 = sigPoints[i], p1 = sigPoints[i+1]; + for (let i = 0; i < stroke.lens.length; i++) { + if (d + stroke.lens[i] >= dist) { + const t = stroke.lens[i] > 0 ? (dist - d) / stroke.lens[i] : 0; + const p0 = stroke.pts[i], p1 = stroke.pts[i+1]; return { x: p0.x + (p1.x - p0.x) * t, y: p0.y + (p1.y - p0.y) * t }; } - d += segLengths[i]; + d += stroke.lens[i]; } - return sigPoints[sigPoints.length - 1]; + return stroke.pts[stroke.pts.length - 1]; } + const totalLength = strokeData.reduce((s, d) => s + d.total, 0); + // ── State ── + let currentStroke = 0; let drawnLength = 0; const drawSpeed = totalLength / 3.0; - let prevTip = sigPoints[0]; + let prevTip = strokes[0][0]; let sparks = []; - let phase = 'drawing'; + let phase = 'drawing'; // drawing, lifting, holding, fading let phaseTimer = 0; let lastTime = 0; - // Track all drawn points for smooth rendering - const drawnPts = []; + // Track drawn points per stroke for smooth rendering + const allDrawnStrokes = [[], []]; function drawBurnTrail() { - if (drawnPts.length < 2) return; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; - // Draw smooth path through all points using quadratic curves - function strokeSmooth(color, width) { + function strokeSmooth(pts, color, width) { + if (pts.length < 2) return; ctx.beginPath(); - ctx.moveTo(drawnPts[0].x, drawnPts[0].y); - for (let i = 1; i < drawnPts.length - 1; i++) { - const mx = (drawnPts[i].x + drawnPts[i+1].x) / 2; - const my = (drawnPts[i].y + drawnPts[i+1].y) / 2; - ctx.quadraticCurveTo(drawnPts[i].x, drawnPts[i].y, mx, my); + ctx.moveTo(pts[0].x, pts[0].y); + for (let i = 1; i < pts.length - 1; i++) { + const mx = (pts[i].x + pts[i+1].x) / 2; + const my = (pts[i].y + pts[i+1].y) / 2; + ctx.quadraticCurveTo(pts[i].x, pts[i].y, mx, my); } - const last = drawnPts[drawnPts.length - 1]; - ctx.lineTo(last.x, last.y); + ctx.lineTo(pts[pts.length-1].x, pts[pts.length-1].y); ctx.strokeStyle = color; ctx.lineWidth = width; ctx.stroke(); } - strokeSmooth('rgba(180, 100, 30, 0.12)', 5); - strokeSmooth('rgba(220, 140, 50, 0.3)', 2.5); - strokeSmooth('rgba(255, 210, 130, 0.7)', 1.2); - strokeSmooth('rgba(255, 248, 235, 0.6)', 0.4); + // Draw all accumulated strokes + for (const pts of allDrawnStrokes) { + strokeSmooth(pts, 'rgba(180, 100, 30, 0.12)', 5); + strokeSmooth(pts, 'rgba(220, 140, 50, 0.3)', 2.5); + strokeSmooth(pts, 'rgba(255, 210, 130, 0.7)', 1.2); + strokeSmooth(pts, 'rgba(255, 248, 235, 0.6)', 0.4); + } } function emitSparks(x, y, count) { @@ -180,23 +204,42 @@ export default { lastTime = timestamp; switch (phase) { - case 'drawing': + case 'drawing': { + const sd = strokeData[currentStroke]; drawnLength += drawSpeed * dt; - if (drawnLength >= totalLength) { - drawnLength = totalLength; - phase = 'holding'; - phaseTimer = 0; - emitSparks(prevTip.x, prevTip.y, 8); + if (drawnLength >= sd.total) { + drawnLength = sd.total; + emitSparks(prevTip.x, prevTip.y, 6); + if (currentStroke < strokes.length - 1) { + // Lift — pause briefly before starting next stroke + phase = 'lifting'; + phaseTimer = 0; + } else { + phase = 'holding'; + phaseTimer = 0; + } } - const tip = posAt(drawnLength); - drawnPts.push({ x: tip.x, y: tip.y }); + const tip = posAtStroke(sd, drawnLength); + allDrawnStrokes[currentStroke].push({ x: tip.x, y: tip.y }); prevTip = tip; if (Math.random() < 0.4) emitSparks(tip.x, tip.y, 1); - // Redraw full smooth trail (clear burn canvas first) + // Redraw full smooth trail ctx.fillStyle = '#0e0d0b'; ctx.fillRect(0, 0, w, h); drawBurnTrail(); break; + } + + case 'lifting': + phaseTimer += dt; + if (phaseTimer >= 0.25) { + currentStroke++; + drawnLength = 0; + prevTip = strokes[currentStroke][0]; + phase = 'drawing'; + phaseTimer = 0; + } + break; case 'holding': phaseTimer += dt; @@ -210,8 +253,11 @@ export default { if (phaseTimer >= 2.0) { ctx.fillStyle = '#0e0d0b'; ctx.fillRect(0, 0, w, h); - drawnLength = 0; prevTip = sigPoints[0]; - sparks = []; drawnPts.length = 0; + currentStroke = 0; drawnLength = 0; + prevTip = strokes[0][0]; + sparks = []; + allDrawnStrokes[0].length = 0; + allDrawnStrokes[1].length = 0; phase = 'drawing'; phaseTimer = 0; } break; @@ -255,8 +301,8 @@ export default { } // Draw laser tip on overlay - if (phase === 'drawing' && drawnLength < totalLength) { - const tip = posAt(drawnLength); + if (phase === 'drawing' && drawnLength < strokeData[currentStroke].total) { + const tip = posAtStroke(strokeData[currentStroke], drawnLength); const fl = 0.85 + Math.random() * 0.15; // Wide heat bloom diff --git a/source/skills/overdrive/SKILL.md b/source/skills/overdrive/SKILL.md index 9e2b5a155..2307e0d70 100644 --- a/source/skills/overdrive/SKILL.md +++ b/source/skills/overdrive/SKILL.md @@ -1,6 +1,6 @@ --- name: overdrive -description: Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or real-time collaboration — make users ask "how did they do that?" +description: Push interfaces past conventional limits with technically ambitious implementations. Whether that's a shader, a 60fps virtual table, spring physics on a dialog, or scroll-driven reveals — make users ask "how did they do that?" args: - name: target description: The feature or area to push into overdrive (optional) @@ -28,8 +28,8 @@ Pages, hero sections, landing pages, portfolios — the "wow" is often sensory: ### For functional UI Tables, forms, dialogs, navigation — the "wow" is in how it FEELS: a dialog that morphs from the button that triggered it via View Transitions, a data table that renders 100k rows at 60fps via virtual scrolling, a form with streaming validation that feels instant, drag-and-drop with spring physics. -### For application architecture -The "wow" is invisible but felt: offline-first with service workers (the app works on a plane), real-time collaboration (cursors appearing as someone else types), near-native computation via WASM, background processing via Web Workers that never blocks the UI. +### For performance-critical UI +The "wow" is invisible but felt: a search that filters 50k items without a flicker, a complex form that never blocks the main thread, an image editor that processes in near-real-time. The interface just never hesitates. ### For data-heavy interfaces Charts and dashboards — the "wow" is in fluidity: GPU-accelerated rendering via Canvas/WebGL for massive datasets, animated transitions between data states, force-directed graph layouts that settle naturally. @@ -66,17 +66,14 @@ Organized by what you're trying to achieve, not by technology name. ### Push performance boundaries - **Web Workers** — move computation off the main thread. Heavy data processing, image manipulation, search indexing — anything that would cause jank. - **OffscreenCanvas** — render in a Worker thread. The main thread stays free while complex visuals render in the background. -- **WASM** — near-native performance for computation-heavy features. Image processing, encryption, physics simulations, codecs. -- **Service Workers** — offline-first experiences, background sync, push notifications. The app works without a network. - -### Enable real-time collaboration -- **WebSockets / SSE** — live cursors, collaborative editing, streaming updates. The interface feels alive. -- **SharedArrayBuffer** — shared memory between threads for high-performance real-time data. +- **WASM** — near-native performance for computation-heavy features. Image processing, physics simulations, codecs. ### Interact with the device - **Web Audio API** — spatial audio, audio-reactive visualizations, sonic feedback. Requires user gesture to start. - **Device APIs** — orientation, ambient light, geolocation. Use sparingly and always with user permission. +**NOTE**: This skill is about enhancing how an interface FEELS, not changing what a product DOES. Adding real-time collaboration, offline support, or new backend capabilities are product decisions, not UI enhancements. Focus on making existing features feel extraordinary. + ## Implement with Discipline ### Progressive enhancement is non-negotiable From fcc70fd4c92878bf1cc79fa5e1ddb17ca650ac8f Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 11:45:30 -0700 Subject: [PATCH 11/14] Require direction confirmation and browser iteration for overdrive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two new mandatory sections in the skill: 1. Propose Before Building — must present 2-3 directions with trade-offs and get user confirmation before writing code. This skill has the highest misfire potential. 2. Iterate with Browser Automation — must use browser tools to visually verify effects and iterate. Complex effects never work on the first try. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/overdrive/SKILL.md | 14 ++++++++++++++ source/skills/overdrive/SKILL.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.claude/skills/overdrive/SKILL.md b/.claude/skills/overdrive/SKILL.md index ef701878f..3d29932c6 100644 --- a/.claude/skills/overdrive/SKILL.md +++ b/.claude/skills/overdrive/SKILL.md @@ -16,6 +16,20 @@ Use the frontend-design skill — it contains design principles, anti-patterns, **EXTRA IMPORTANT FOR THIS SKILL**: Context determines what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate. +### Propose Before Building + +This skill has the highest potential to misfire. Do NOT jump straight into implementation. You MUST: + +1. **Think through 2-3 different directions** — consider different techniques, levels of ambition, and aesthetic approaches. For each direction, briefly describe what the result would look and feel like. +2. **STOP and call the AskUserQuestion tool to clarify.** to present these directions and get the user's pick before writing any code. Explain trade-offs (browser support, performance cost, complexity). +3. Only proceed with the direction the user confirms. + +Skipping this step risks building something embarrassing that needs to be thrown away. + +### Iterate with Browser Automation + +Technically ambitious effects almost never work on the first try. You MUST actively use browser automation tools to preview your work, visually verify the result, and iterate. Do not assume the effect looks right — check it. Expect multiple rounds of refinement. The gap between "technically works" and "looks extraordinary" is closed through visual iteration, not code alone. + --- ## Assess What "Extraordinary" Means Here diff --git a/source/skills/overdrive/SKILL.md b/source/skills/overdrive/SKILL.md index 2307e0d70..5beeb4410 100644 --- a/source/skills/overdrive/SKILL.md +++ b/source/skills/overdrive/SKILL.md @@ -16,6 +16,20 @@ Use the frontend-design skill — it contains design principles, anti-patterns, **EXTRA IMPORTANT FOR THIS SKILL**: Context determines what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate. +### Propose Before Building + +This skill has the highest potential to misfire. Do NOT jump straight into implementation. You MUST: + +1. **Think through 2-3 different directions** — consider different techniques, levels of ambition, and aesthetic approaches. For each direction, briefly describe what the result would look and feel like. +2. **{{ask_instruction}}** to present these directions and get the user's pick before writing any code. Explain trade-offs (browser support, performance cost, complexity). +3. Only proceed with the direction the user confirms. + +Skipping this step risks building something embarrassing that needs to be thrown away. + +### Iterate with Browser Automation + +Technically ambitious effects almost never work on the first try. You MUST actively use browser automation tools to preview your work, visually verify the result, and iterate. Do not assume the effect looks right — check it. Expect multiple rounds of refinement. The gap between "technically works" and "looks extraordinary" is closed through visual iteration, not code alone. + --- ## Assess What "Extraordinary" Means Here From 61eaceefddac29db3af1052285f9a1467c60f70c Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 15:51:55 -0700 Subject: [PATCH 12/14] Add overdrive ASCII banner on skill activation Starts the response with a distinctive speed-line banner to set the tone for the skill. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/skills/overdrive/SKILL.md | 7 +++++++ source/skills/overdrive/SKILL.md | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/.claude/skills/overdrive/SKILL.md b/.claude/skills/overdrive/SKILL.md index 3d29932c6..c3f1bb0cd 100644 --- a/.claude/skills/overdrive/SKILL.md +++ b/.claude/skills/overdrive/SKILL.md @@ -8,6 +8,13 @@ args: required: false --- +Start your response with: + +``` +──────────── ⚡ OVERDRIVE ───────────── +》》》 Entering overdrive mode... +``` + Push an interface past conventional limits. This isn't just about visual effects — it's about using the full power of the browser to make any part of an interface feel extraordinary: a table that handles a million rows, a dialog that morphs from its trigger, a form that validates in real-time with streaming feedback, a page transition that feels cinematic. ## MANDATORY PREPARATION diff --git a/source/skills/overdrive/SKILL.md b/source/skills/overdrive/SKILL.md index 5beeb4410..b600d3938 100644 --- a/source/skills/overdrive/SKILL.md +++ b/source/skills/overdrive/SKILL.md @@ -8,6 +8,13 @@ args: user-invokable: true --- +Start your response with: + +``` +──────────── ⚡ OVERDRIVE ───────────── +》》》 Entering overdrive mode... +``` + Push an interface past conventional limits. This isn't just about visual effects — it's about using the full power of the browser to make any part of an interface feel extraordinary: a table that handles a million rows, a dialog that morphs from its trigger, a form that validates in real-time with streaming feedback, a page transition that feels cinematic. ## MANDATORY PREPARATION From 8863e5d07b6c5c8e9dcf0383d0db6377c9083570 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 15:58:25 -0700 Subject: [PATCH 13/14] Bump version to 1.5.0, add changelog entry New in v1.5.0: - 3 new skills: /typeset, /arrange, /overdrive (beta) - Shared Context Gathering Protocol with .impeccable.md - teach-impeccable writes provider-agnostic context - Deep linking to commands (#cmd-overdrive etc.) - JS-powered demo infrastructure with live laser signature Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- package.json | 2 +- public/index.html | 16 +++++++++++++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 3787cbe17..fe7b61e15 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -12,7 +12,7 @@ { "name": "impeccable", "description": "Design vocabulary and skills for frontend development. Includes 20 commands (/polish, /distill, /audit, /typeset, /overdrive, etc.) and an enhanced frontend-design skill with curated anti-patterns.", - "version": "1.3.0", + "version": "1.5.0", "author": { "name": "Paul Bakaus", "email": "paul@paulbakaus.com" diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 1798439b6..e52c30e23 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "impeccable", "description": "Design vocabulary and skills for frontend development. Includes 21 skills (20 user-invokable: /polish, /distill, /audit, /typeset, /overdrive, etc.) and an enhanced frontend-design skill with curated anti-patterns.", - "version": "1.3.0", + "version": "1.5.0", "author": { "name": "Paul Bakaus", "email": "paul@paulbakaus.com" diff --git a/package.json b/package.json index 2262c1b2f..378ecc2f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "impeccable", - "version": "1.3.0", + "version": "1.5.0", "author": "Paul Bakaus", "dependencies": { "archiver": "^7.0.1", diff --git a/public/index.html b/public/index.html index c5d00baa4..a42c6e7d2 100644 --- a/public/index.html +++ b/public/index.html @@ -78,7 +78,7 @@
- +
@@ -310,6 +310,20 @@
+
+
+ v1.5.0 + March 16, 2026 +
+
    +
  • 3 new skills: /typeset (fix typography), /arrange (fix layout & spacing), /overdrive (technically extraordinary effects, beta)
  • +
  • Shared Context Gathering Protocol — all skills now check .impeccable.md and auto-invoke /teach-impeccable when needed
  • +
  • /teach-impeccable now writes to .impeccable.md for provider-agnostic context
  • +
  • Deep linking to commands (#cmd-overdrive, etc.)
  • +
  • JS-powered demo support — /overdrive features a live laser-etched signature effect
  • +
+
+
v1.3.0 From eede3214586b04be9bb85ef4b05c95ffbea582bd Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Mon, 16 Mar 2026 15:59:09 -0700 Subject: [PATCH 14/14] Trim changelog to user-facing highlights Co-Authored-By: Claude Opus 4.6 (1M context) --- public/index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/index.html b/public/index.html index a42c6e7d2..cadec91c5 100644 --- a/public/index.html +++ b/public/index.html @@ -317,10 +317,8 @@
  • 3 new skills: /typeset (fix typography), /arrange (fix layout & spacing), /overdrive (technically extraordinary effects, beta)
  • -
  • Shared Context Gathering Protocol — all skills now check .impeccable.md and auto-invoke /teach-impeccable when needed
  • -
  • /teach-impeccable now writes to .impeccable.md for provider-agnostic context
  • +
  • Skills now auto-gather design context via .impeccable.md — run /teach-impeccable once, all skills benefit
  • Deep linking to commands (#cmd-overdrive, etc.)
  • -
  • JS-powered demo support — /overdrive features a live laser-etched signature effect