Restructure narrative: Foundation, Language, Antidote, Visual Mode

Major site restructure reflecting Impeccable's expanded value prop:
- 01 The Foundation: 7 design dimensions, 212 guidelines grid
- 02 The Language: merged periodic table + Commands in Action
- 03 The Antidote: moved from position 1, anti-patterns + gallery
- 04 Visual Mode: live iframe embed of detection overlay demo
- Composite demo page combining purple gradients + side-tab cards
- Updated hero copy (212 guidelines, 22 commands)
- 7-item sticky nav, backward-compat anchor aliases

Detection overlay improvements:
- Staggered entrance animation (80ms per element)
- Banner slides in from top
- Skip body/html from overlay targeting (fixes scrollbar bug)
- Banner overflow: hidden + maxWidth: 100vw
- CLAUDE.md: document that browser script is generated, never edit directly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Bakaus
2026-04-02 19:56:29 -07:00
co-authored by Claude Opus 4.6
parent 4b356a6b5b
commit 03a4433dcc
11 changed files with 646 additions and 5141 deletions
@@ -1208,11 +1208,20 @@ if (IS_BROWSER) {
// Inject hover styles via CSS (more reliable than JS event listeners)
const styleEl = document.createElement('style');
styleEl.textContent = `
@keyframes impeccable-reveal {
from { opacity: 0; outline-color: transparent; }
to { opacity: 1; outline-color: ${OUTLINE_COLOR}; }
}
.impeccable-overlay:not(.impeccable-banner) {
pointer-events: none;
outline: 2px solid ${OUTLINE_COLOR};
border-radius: 4px;
transition: outline-color 0.3s ease;
animation: impeccable-reveal 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
animation-play-state: paused;
}
.impeccable-overlay.impeccable-visible {
animation-play-state: running;
}
.impeccable-overlay.impeccable-hover {
outline-color: rgba(0,0,0,0.85);
@@ -1285,6 +1294,7 @@ if (IS_BROWSER) {
// Uses a huge rootMargin so all *rendered* elements count as intersecting,
// while display:none / closed <details> / hidden modals etc. do not.
// This is event-driven -- no polling needed.
let overlayIndex = 0;
const visibilityObserver = new IntersectionObserver((entries) => {
for (const entry of entries) {
const overlay = entry.target._impeccableOverlay;
@@ -1292,6 +1302,11 @@ if (IS_BROWSER) {
if (entry.isIntersecting) {
overlay.style.display = '';
positionOverlay(overlay);
if (!overlay._revealed) {
overlay._revealed = true;
overlay.style.animationDelay = `${(overlay._staggerIndex || 0) * 80}ms`;
requestAnimationFrame(() => overlay.classList.add('impeccable-visible'));
}
} else {
overlay.style.display = 'none';
}
@@ -1358,6 +1373,7 @@ if (IS_BROWSER) {
// Start hidden; the IntersectionObserver will show it once the target is rendered
outline.style.display = 'none';
outline._staggerIndex = overlayIndex++;
el._impeccableOverlay = outline;
visibilityObserver.observe(el);
@@ -1378,8 +1394,13 @@ if (IS_BROWSER) {
background: LABEL_BG, color: 'white',
fontFamily: 'system-ui, sans-serif', fontSize: '13px',
display: 'flex', alignItems: 'center', pointerEvents: 'auto',
height: '36px',
height: '36px', overflow: 'hidden', maxWidth: '100vw',
transform: 'translateY(-100%)',
transition: 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1)',
});
requestAnimationFrame(() => requestAnimationFrame(() => {
banner.style.transform = 'translateY(0)';
}));
// Scrollable findings area
const scrollArea = document.createElement('div');
@@ -1473,6 +1494,8 @@ if (IS_BROWSER) {
// Skip browser extension elements (Claude, etc.)
const elId = el.id || '';
if (elId.startsWith('claude-') || elId.startsWith('cic-')) continue;
// Skip html/body -- page-level findings go in the banner, not a full-page overlay
if (el === document.body || el === document.documentElement) continue;
const findings = [
...checkElementBordersDOM(el).map(f => ({ type: f.id, detail: f.snippet })),