New /visual-mode top-level page, pull gallery out of /anti-patterns

The 'In the wild' section at the bottom of /anti-patterns was
mischaracterizing synthetic fixtures as real examples and was buried
deep in a taxonomy of detection rules. The specimens belong somewhere
that frames them as what they actually are: live pages you can click
into to experience Visual Mode. Split them off into a new top-level
page that also finally gives Visual Mode first-class treatment.

- New /visual-mode page, top-level nav item, single-column layout (no
  sidebar). Structure:
    1. Editorial header with an "Live detection overlay" eyebrow.
    2. Live iframe embed of visual-mode-demo.html inside mac-window
       chrome, same preview component the homepage uses.
    3. "Three ways to run it" section with three method cards:
         - /critique runs the overlay inside its browser pass
         - `npx impeccable live` starts a standalone overlay server
         - Chrome extension, marked coming soon, with a cream bg
    4. "Try it live" gallery of the 11 synthetic specimens as
       clickable cards. Each links to /antipattern-examples/{id}.html
       where the detector script is already injected so the reader
       lands on a live overlay.
- scripts/build-sub-pages.js: new renderVisualModeMain(); visualMode
  added to outDirs; generator loop writes /visual-mode/index.html.
- server/index.js: new /visual-mode route serving the generated file.
- Top nav on every page gains 'Visual Mode' between Anti-Patterns
  and the GitHub pill. Updated the partial + all 4 hand-authored
  HTML pages.
- .gitignore adds public/visual-mode/.

- /anti-patterns: 'In the wild' section and its TOC entry removed.
  Replaced with a one-line pointer at the end of the lede: "Want to
  see them live on real pages? Try Visual Mode." GALLERY_ITEMS stays
  in the catalog file (now used by /visual-mode only).

- public/css/sub-pages.css: new .visual-mode-page-body + .visual-mode-*
  classes. Ports the mac-window chrome (dots + mono title) from
  main.css, adds three-card method grid, and reuses the existing
  .gallery-card styles for the specimen list.

Clean up a few em-dashes in the catalog (block comments + one visible
visual example) so the build-time validator stays clean.

Server restart required to pick up the new /visual-mode route.
This commit is contained in:
Paul Bakaus
2026-04-08 13:04:23 -07:00
parent ebe07cbae5
commit 27d1b13bc2
10 changed files with 315 additions and 39 deletions
+201
View File
@@ -1105,6 +1105,207 @@ main#main {
max-width: 65ch;
}
/* ============================================
VISUAL MODE PAGE
============================================ */
.visual-mode-page-body main#main {
/* Reset the docs-layout override; this page uses its own max-width. */
max-width: none;
margin: 0;
padding: 0;
}
.visual-mode-page {
max-width: 1100px;
margin: 0 auto;
padding: clamp(2rem, 4vw, 3.5rem) clamp(var(--spacing-md), 4vw, var(--spacing-2xl)) clamp(4rem, 8vw, 6rem);
}
.visual-mode-page-header {
max-width: 720px;
margin-bottom: clamp(2.5rem, 5vw, 3.5rem);
}
.visual-mode-demo-wrap {
margin-bottom: clamp(3rem, 6vw, 4.5rem);
}
.visual-mode-demo-caption {
font-size: 0.8125rem;
color: var(--color-ash);
font-style: italic;
margin-top: var(--spacing-sm);
text-align: center;
}
/* Mac-window chrome around the iframe (same shape as the homepage
preview; ported here so sub-pages.css is self-contained). */
.visual-mode-preview {
border-radius: 10px;
overflow: hidden;
border: 1px solid var(--color-mist);
box-shadow: 0 12px 40px -8px rgba(0, 0, 0, 0.12);
max-width: 1040px;
margin: 0 auto;
}
.visual-mode-preview-header {
display: flex;
align-items: center;
gap: 6px;
padding: 10px 14px;
background: var(--color-cream);
border-bottom: 1px solid var(--color-mist);
}
.visual-mode-preview-dot {
width: 10px;
height: 10px;
border-radius: 50%;
flex-shrink: 0;
}
.visual-mode-preview-dot.red { background: #ff5f56; }
.visual-mode-preview-dot.yellow { background: #ffbd2e; }
.visual-mode-preview-dot.green { background: #27c93f; }
.visual-mode-preview-title {
margin-left: auto;
font-family: var(--font-mono);
font-size: 0.75rem;
color: var(--color-ash);
}
.visual-mode-frame {
display: block;
width: 100%;
height: 580px;
border: none;
background: white;
}
/* Three invocation methods. */
.visual-mode-methods {
margin-bottom: clamp(3rem, 6vw, 4.5rem);
}
.visual-mode-methods-title {
font-family: var(--font-display);
font-size: clamp(1.75rem, 3vw, 2.25rem);
font-weight: 500;
font-style: italic;
color: var(--color-ink);
letter-spacing: -0.01em;
margin-bottom: var(--spacing-lg);
}
.visual-mode-methods-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: var(--spacing-md);
}
.visual-mode-method {
padding: var(--spacing-lg);
background: var(--color-paper);
border: 1px solid var(--color-mist);
border-radius: 10px;
display: flex;
flex-direction: column;
gap: 8px;
transition: border-color var(--duration-fast) var(--ease-out);
}
.visual-mode-method:hover {
border-color: var(--color-ash);
}
.visual-mode-method[data-coming-soon] {
background: var(--color-cream);
}
.visual-mode-method-label {
font-family: var(--font-mono);
font-size: 0.625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.14em;
color: var(--color-accent);
}
.visual-mode-method-name {
font-family: var(--font-display);
font-size: 1.375rem;
font-style: italic;
font-weight: 500;
color: var(--color-ink);
line-height: 1.25;
}
.visual-mode-method-name a {
color: inherit;
text-decoration: none;
border-bottom: 1px solid var(--color-accent);
}
.visual-mode-method-name a:hover {
color: var(--color-accent);
}
.visual-mode-method-name code {
font-family: var(--font-mono);
font-size: 0.875em;
font-style: normal;
background: var(--color-cream);
border: 1px solid var(--color-mist);
padding: 2px 8px;
border-radius: 4px;
color: var(--color-ink);
}
.visual-mode-method-desc {
font-size: 0.9375rem;
line-height: 1.6;
color: var(--color-charcoal);
flex: 1;
}
.visual-mode-method-desc a {
color: var(--color-ink);
text-decoration: none;
border-bottom: 1px solid var(--color-accent);
font-family: var(--font-mono);
font-size: 0.875em;
font-weight: 500;
}
.visual-mode-method-desc a:hover {
color: var(--color-accent);
}
/* Gallery (specimens) section */
.visual-mode-gallery-header {
margin-bottom: var(--spacing-lg);
}
.visual-mode-gallery-title {
font-family: var(--font-display);
font-size: clamp(1.75rem, 3vw, 2.25rem);
font-weight: 500;
font-style: italic;
color: var(--color-ink);
letter-spacing: -0.01em;
margin-bottom: var(--spacing-sm);
}
.visual-mode-gallery-lede {
font-size: 0.9375rem;
line-height: 1.6;
color: var(--color-charcoal);
max-width: 60ch;
}
/* ============================================
ANTI-PATTERNS: IN THE WILD (merged gallery)
============================================ */