Files
pbakaus_impeccable/tests/fixtures/antipatterns/italic-serif-display.html
T
444e4acad3 Detector: add italic-serif display headline + hero eyebrow chip rules (#127) (#129)
* feat(detector): flag italic-serif display heroes and uppercase eyebrow chips (#127)

Two new rules covering the structural tells of late-2025/early-2026
AI-generated marketing pages.

- italic-serif-display: oversized italic serif (Fraunces, Recoleta,
  Newsreader, Playfair, Cormorant, Tiempos, ...) as the primary hero
  headline. Anchored on h1 (or h2 at >= 48px) with font-style: italic
  and a serif primary face.
- hero-eyebrow-chip: uppercase letter-spaced label sitting as the
  previousElementSibling of a hero h1 (font-size >= 48px). Bounded
  text length 2-30 chars, letter-spacing >= 1.6px, font-size <= 14px.
  The pill-chip variant (background + border-radius: 999px) falls out
  of the same gates for free.

Both follow the existing icon-tile-stack pattern: pure check function +
browser DOM adapter + jsdom adapter, wired into both element loops.
Two-column fixtures (4 flag / 6 pass each) drive the jsdom tests.

Skill copy in source/skills/impeccable/reference/typography.md and
critique.md calls out the patterns by name. The italic-serif rule's
description acknowledges that editorial/magazine register may legitimately
want the pattern -- judge by context.

Closes #127

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add sandbox gotchas for Codex

* Trim verbose detector skill copy

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Paul Bakaus <paulbakaus@pauls-mbp-3.lan>
2026-05-02 12:01:43 -07:00

191 lines
6.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Italic-Serif-Display — Should Flag vs Should Pass</title>
<style>
/* ─── Layout convention: two-column fixture ─────────────────────────
Left column = patterns the rule SHOULD flag.
Right column = legitimate patterns the rule should NOT flag.
Each test case is annotated with a unique <h1>/<h2>/<blockquote>
text so the test can match snippets back to expectations.
──────────────────────────────────────────────────────────────── */
body { font-family: system-ui, sans-serif; margin: 0; padding: 24px; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; max-width: 1200px; margin: 0 auto; }
.col h2.col-label { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 16px; color: #475569; }
.case { margin-bottom: 32px; padding: 24px; border: 1px solid #e2e8f0; border-radius: 12px; background: #fff; }
.case p { font-size: 14px; margin: 12px 0 0; color: #64748b; }
/* ── FLAG cases ── */
/* 1: Fraunces 88px italic — the Lumina hero pattern */
.hero-fraunces {
font-family: 'Fraunces', Georgia, serif;
font-style: italic;
font-size: 88px;
font-weight: 400;
line-height: 1.05;
margin: 0;
}
/* 2: Recoleta 64px italic */
.hero-recoleta {
font-family: 'Recoleta', serif;
font-style: italic;
font-size: 64px;
font-weight: 400;
margin: 0;
}
/* 3: Playfair Display 72px italic */
.hero-playfair {
font-family: 'Playfair Display', serif;
font-style: italic;
font-size: 72px;
font-weight: 500;
margin: 0;
}
/* 4: Unknown serif primary, but generic `serif` fallback in stack */
.hero-unknown-serif {
font-family: 'CustomSerifFace', serif;
font-style: italic;
font-size: 56px;
font-weight: 400;
margin: 0;
}
/* ── PASS cases ── */
/* a: italic, but sans-serif primary (Karla) — italic display in a sans is rare and usually intentional */
.pass-sans-italic {
font-family: 'Karla', sans-serif;
font-style: italic;
font-size: 64px;
font-weight: 600;
margin: 0;
}
/* b: serif at 88px, but font-style: normal */
.pass-roman-serif {
font-family: 'Fraunces', Georgia, serif;
font-style: normal;
font-size: 88px;
font-weight: 600;
margin: 0;
}
/* c: italic serif blockquote at 24px (genuine pull quote, not a hero) */
.pass-pull-quote {
font-family: 'Fraunces', Georgia, serif;
font-style: italic;
font-size: 24px;
font-weight: 400;
margin: 0;
color: #334155;
}
/* d: roman h1 with an italic <em> inside — v1 explicitly does NOT flag this */
.pass-roman-h1-em-italic {
font-family: 'Inter', sans-serif;
font-style: normal;
font-size: 72px;
font-weight: 600;
margin: 0;
}
.pass-roman-h1-em-italic em {
font-family: 'Fraunces', Georgia, serif;
font-style: italic;
font-weight: 400;
}
/* e: italic serif h2 at 32px — under the 48px hero threshold */
.pass-italic-serif-32 {
font-family: 'Fraunces', Georgia, serif;
font-style: italic;
font-size: 32px;
font-weight: 400;
margin: 0;
}
/* f: baseline-clean h1 — sans-serif roman */
.pass-h1-sans-roman {
font-family: 'Inter', sans-serif;
font-style: normal;
font-size: 64px;
font-weight: 700;
margin: 0;
}
</style>
</head>
<body>
<div class="grid">
<!-- ════════════════════════════════════════════════════════════════
LEFT COLUMN: should flag
═══════════════════════════════════════════════════════════════ -->
<div class="col" data-col="flag">
<h2 class="col-label">Should flag</h2>
<div class="case">
<h1 class="hero-fraunces">Fraunces 88px italic</h1>
<p>The Lumina hero pattern: oversized Fraunces italic display.</p>
</div>
<div class="case">
<h1 class="hero-recoleta">Recoleta 64px italic</h1>
<p>Recoleta italic at 64px, generic serif fallback.</p>
</div>
<div class="case">
<h1 class="hero-playfair">Playfair 72px italic</h1>
<p>Playfair Display italic at hero scale.</p>
</div>
<div class="case">
<h1 class="hero-unknown-serif">Unknown Serif Generic Fallback</h1>
<p>Primary font unknown to the detector, but the stack ends in generic serif.</p>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════
RIGHT COLUMN: should pass
═══════════════════════════════════════════════════════════════ -->
<div class="col" data-col="pass">
<h2 class="col-label">Should pass</h2>
<div class="case">
<h1 class="pass-sans-italic">Sans Italic Display</h1>
<p>Italic at hero scale, but in a sans-serif face.</p>
</div>
<div class="case">
<h1 class="pass-roman-serif">Roman Serif Display</h1>
<p>Fraunces at 88px, but font-style is normal (not italic).</p>
</div>
<div class="case">
<blockquote class="pass-pull-quote">Italic Serif Pull Quote</blockquote>
<p>Italic serif at 24px is a legitimate pull-quote pattern, not a hero.</p>
</div>
<div class="case">
<h1 class="pass-roman-h1-em-italic">Inline Em Inside <em>Roman</em></h1>
<p>Roman h1 with an inline italic em — v1 deliberately does not flag this.</p>
</div>
<div class="case">
<h2 class="pass-italic-serif-32">Italic Serif at 32px</h2>
<p>Italic serif h2 below the 48px hero threshold.</p>
</div>
<div class="case">
<h1 class="pass-h1-sans-roman">h1 Sans-Serif Roman</h1>
<p>Baseline-clean control: sans-serif, roman, hero scale.</p>
</div>
</div>
</div>
</body>
</html>