mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-20 18:16:30 +03:00
Ban kickers outright: one eyebrow above a heading is one too many
The detector's repeated-section-kickers rule waited for three tracked labels before calling the pattern; generated pages earn the finding on the first one. Retire that id and replace it with kicker-above-heading, which flags any tracked-caps or small-caps label block sitting directly above an h1-h4 or heading-role element, at full warning severity. The candidate gate absorbs the false-positive shapes the repetition count used to paper over: editorial category-and-date meta lines, breadcrumbs with separators, legal and chapter numbering, application panel context labels, nav landmarks before page titles, and stat callouts with the label below the number. Hero-scale h1 eyebrows stay with hero-eyebrow-chip so one element gets one finding, and the static cascade now carries font-variant so small-caps kickers register. The craft floor entry moves from caution to ban in the same breath. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
806a48aef2
commit
33a1c5fcae
@@ -912,50 +912,63 @@ describe('detectHtml — hero-eyebrow-chip', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectHtml — repeated-section-kickers', () => {
|
||||
describe('detectHtml — kicker-above-heading', () => {
|
||||
const SHOULD_FLAG = [
|
||||
'The Future Is Admitted',
|
||||
'A Private Rehearsal',
|
||||
'Reviewed, Not Sold',
|
||||
'Touch the Future',
|
||||
'A Single Kicker Still Flags',
|
||||
'Kicker Above An H3',
|
||||
'Kicker Above An H4',
|
||||
'Sub Hero Heading',
|
||||
'Small Caps Kicker',
|
||||
'Heading Role Kicker',
|
||||
];
|
||||
const SHOULD_PASS = [
|
||||
'Breadcrumb Before Heading',
|
||||
'Breadcrumb Trail Outside Nav',
|
||||
'Dateline Above Headline',
|
||||
'Editorial Card Meta',
|
||||
'Form Heading Is Separate',
|
||||
'Step Indicator',
|
||||
'Figure Caption Label',
|
||||
'Normal Case Kicker',
|
||||
'Limitation Of Liability',
|
||||
'Indemnification Clause',
|
||||
'Chapter Numbering Passes',
|
||||
'Application Panel Context',
|
||||
'Page Title After Nav',
|
||||
'48%',
|
||||
'Sentence Case Lead In',
|
||||
'Untracked Caps Label',
|
||||
'Intentional Brand Label',
|
||||
'Hero Owned By Hero Rule',
|
||||
'Garden Suite',
|
||||
'Sea Loft',
|
||||
'Cliff Suite',
|
||||
'/impeccabletypeset',
|
||||
'/impeccablelayout',
|
||||
'/impeccablecolorize',
|
||||
'/impeccablecraft',
|
||||
'/impeccableaudit',
|
||||
'/impeccablepolish',
|
||||
'Step Indicator',
|
||||
'Mockup Hero Variant One',
|
||||
'Mockup Hero Variant Two',
|
||||
'Mockup Hero Variant Three',
|
||||
];
|
||||
|
||||
it('repeated-section-kickers: flags only repeated section scaffolding', async () => {
|
||||
const f = await detectHtml(path.join(FIXTURES, 'repeated-section-kickers.html'));
|
||||
it('kicker-above-heading: flags any kicker above a heading, without repetition', async () => {
|
||||
const f = await detectHtml(path.join(FIXTURES, 'kicker-above-heading.html'));
|
||||
const flagged = new Set();
|
||||
for (const r of f) {
|
||||
if (r.antipattern !== 'repeated-section-kickers') continue;
|
||||
assert.equal(r.severity, 'advisory');
|
||||
if (r.antipattern !== 'kicker-above-heading') continue;
|
||||
assert.equal(r.severity, 'warning');
|
||||
const matches = [...(r.snippet || '').matchAll(/"([^"]+)"/g)];
|
||||
if (matches.length) flagged.add(matches[matches.length - 1][1]);
|
||||
}
|
||||
|
||||
for (const text of SHOULD_FLAG) {
|
||||
assert.ok(flagged.has(text), `expected "${text}" to be flagged as repeated-section-kickers`);
|
||||
assert.ok(flagged.has(text), `expected "${text}" to be flagged as kicker-above-heading`);
|
||||
}
|
||||
for (const text of SHOULD_PASS) {
|
||||
assert.ok(!flagged.has(text), `"${text}" should NOT be flagged as repeated-section-kickers`);
|
||||
assert.ok(!flagged.has(text), `"${text}" should NOT be flagged as kicker-above-heading`);
|
||||
}
|
||||
|
||||
// The retired repeated-section-kickers id must never resurface.
|
||||
assert.ok(!f.some(r => r.antipattern === 'repeated-section-kickers'),
|
||||
'retired rule id repeated-section-kickers should not fire');
|
||||
|
||||
// The hero-scale h1 eyebrow stays with hero-eyebrow-chip, exactly once.
|
||||
const heroHits = f.filter(r => r.antipattern === 'hero-eyebrow-chip'
|
||||
&& /Hero Owned By Hero Rule/.test(r.snippet || ''));
|
||||
assert.equal(heroHits.length, 1, 'hero-eyebrow-chip should own the hero-scale h1 eyebrow');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Kicker Above Heading Fixture</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f6f2ec;
|
||||
color: #171411;
|
||||
}
|
||||
main {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 32px;
|
||||
padding: 32px;
|
||||
}
|
||||
.col {
|
||||
min-width: 0;
|
||||
border: 1px solid #c9bfb2;
|
||||
padding: 24px;
|
||||
}
|
||||
.case {
|
||||
min-height: 120px;
|
||||
margin: 0 0 24px;
|
||||
padding: 16px;
|
||||
background: #fffaf3;
|
||||
}
|
||||
.kicker,
|
||||
.pass-kicker,
|
||||
.pass-kicker-caps {
|
||||
display: block;
|
||||
width: 240px;
|
||||
min-height: 16px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.11em;
|
||||
color: #5b5046;
|
||||
}
|
||||
.kicker,
|
||||
.pass-kicker-caps {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.smallcaps-kicker {
|
||||
display: block;
|
||||
width: 240px;
|
||||
min-height: 16px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.12em;
|
||||
font-variant: small-caps;
|
||||
color: #5b5046;
|
||||
}
|
||||
.untracked-caps {
|
||||
display: block;
|
||||
width: 240px;
|
||||
min-height: 16px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: normal;
|
||||
text-transform: uppercase;
|
||||
color: #5b5046;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 32px;
|
||||
line-height: 38px;
|
||||
font-weight: 700;
|
||||
}
|
||||
h3 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-weight: 700;
|
||||
}
|
||||
h4 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 20px;
|
||||
line-height: 26px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.role-heading {
|
||||
margin: 0 0 12px;
|
||||
font-size: 28px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.hero-h1 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 64px;
|
||||
line-height: 70px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.hero-eyebrow {
|
||||
display: block;
|
||||
width: 240px;
|
||||
min-height: 16px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 2px;
|
||||
text-transform: uppercase;
|
||||
color: #5b5046;
|
||||
}
|
||||
p,
|
||||
label,
|
||||
figcaption,
|
||||
a,
|
||||
li {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
nav,
|
||||
form,
|
||||
figure,
|
||||
ol {
|
||||
margin: 0 0 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
min-height: 80px;
|
||||
}
|
||||
.card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
.suite-card {
|
||||
display: block;
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
background: #fff;
|
||||
}
|
||||
.taxonomy-label {
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.11em;
|
||||
text-transform: uppercase;
|
||||
color: #5b5046;
|
||||
}
|
||||
.suite-card h3 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.stat {
|
||||
min-height: 100px;
|
||||
padding: 16px;
|
||||
background: #fffaf3;
|
||||
}
|
||||
.stat h3 {
|
||||
font-size: 40px;
|
||||
line-height: 46px;
|
||||
}
|
||||
.hidden-mockup {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
.mockup-hero {
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
background: #fff;
|
||||
}
|
||||
.mockup-hero h2 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<section class="col" aria-label="Should flag">
|
||||
<h1>Should flag</h1>
|
||||
|
||||
<section class="case">
|
||||
<span class="kicker">Invitation protocol</span>
|
||||
<h2>"A Single Kicker Still Flags"</h2>
|
||||
<p>One tracked uppercase label above one heading is enough. No repetition required.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<p class="kicker">Preview sequence</p>
|
||||
<h3>"Kicker Above An H3"</h3>
|
||||
<p>Subsection headings get no eyebrow either.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<div class="kicker">Access window</div>
|
||||
<h4>"Kicker Above An H4"</h4>
|
||||
<p>The ban runs down to h4.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="kicker">Platform notes</span>
|
||||
<h1 class="sub-hero">"Sub Hero Heading"</h1>
|
||||
<p>A 32px h1 is below hero scale, so this pair belongs to the general ban.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="smallcaps-kicker">materials briefing</span>
|
||||
<h2>"Small Caps Kicker"</h2>
|
||||
<p>Small-caps styling is the same label in a different costume.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<div class="kicker">Field studies</div>
|
||||
<div role="heading" aria-level="2" class="role-heading">"Heading Role Kicker"</div>
|
||||
<p>Elements carrying a heading role are headings for this rule.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="col" aria-label="Should pass">
|
||||
<h1>Should pass</h1>
|
||||
|
||||
<nav class="case" aria-label="Breadcrumb">
|
||||
<span class="pass-kicker">Home / Journal</span>
|
||||
<h2>"Breadcrumb Before Heading"</h2>
|
||||
<a href="/">Home</a>
|
||||
</nav>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker-caps">Home / Journal / Archive</span>
|
||||
<h2>"Breadcrumb Trail Outside Nav"</h2>
|
||||
<p>A path with separators is wayfinding, not a kicker, even without a nav wrapper.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker-caps">News · Jan 12, 2026</span>
|
||||
<h2>"Dateline Above Headline"</h2>
|
||||
<p>Editorial category-and-date meta lines are content metadata.</p>
|
||||
</section>
|
||||
|
||||
<article class="case">
|
||||
<span class="pass-kicker-caps">Field report</span>
|
||||
<h3>"Editorial Card Meta"</h3>
|
||||
<p>Category labels inside an article card are structured metadata for scanning.</p>
|
||||
</article>
|
||||
|
||||
<form class="case">
|
||||
<label class="pass-kicker" for="guest">Guest name</label>
|
||||
<input id="guest" name="guest" style="width: 220px; height: 40px;">
|
||||
<h2>"Form Heading Is Separate"</h2>
|
||||
</form>
|
||||
|
||||
<figure class="case">
|
||||
<figcaption class="pass-kicker-caps">Plate study</figcaption>
|
||||
<h3>"Figure Caption Label"</h3>
|
||||
</figure>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker-caps">Section 4.2</span>
|
||||
<h2>"Limitation Of Liability"</h2>
|
||||
<p>Legal and document numbering identifies the clause; it is not decoration.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker-caps">§ 12.3</span>
|
||||
<h2>"Indemnification Clause"</h2>
|
||||
<p>Statutory references keep their marker.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker-caps">Chapter Four</span>
|
||||
<h2>"Chapter Numbering Passes"</h2>
|
||||
<p>Spelled-out chapter numbering is document structure, like legal numbering.</p>
|
||||
</section>
|
||||
|
||||
<section class="case" role="tabpanel" aria-label="Saved station">
|
||||
<span class="pass-kicker-caps">Next from</span>
|
||||
<h2>"Application Panel Context"</h2>
|
||||
<p>Context labels inside application panels describe state, not decoration.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<nav aria-label="Primary"><a href="/">Home</a> <a href="/docs">Docs</a></nav>
|
||||
<h1>"Page Title After Nav"</h1>
|
||||
<p>A navigation landmark preceding the page title is chrome, not a kicker.</p>
|
||||
</section>
|
||||
|
||||
<div class="stat">
|
||||
<h3>"48%"</h3>
|
||||
<span class="pass-kicker-caps">Growth yoy</span>
|
||||
<p>Stat callouts put the small label below the number. That direction is legal.</p>
|
||||
</div>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker">A quiet lead-in sentence</span>
|
||||
<h2>"Sentence Case Lead In"</h2>
|
||||
<p>Not uppercase, not small-caps: an ordinary standfirst.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="untracked-caps">New arrivals</span>
|
||||
<h2>"Untracked Caps Label"</h2>
|
||||
<p>Uppercase without tracking lacks the kicker styling signature.</p>
|
||||
</section>
|
||||
|
||||
<section class="case" data-impeccable-allow-kickers>
|
||||
<span class="pass-kicker-caps">Archive code</span>
|
||||
<h2>"Intentional Brand Label"</h2>
|
||||
<p>Deliberate brand systems can opt out with an explicit marker.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<span class="hero-eyebrow">Platform overview</span>
|
||||
<h1 class="hero-h1">"Hero Owned By Hero Rule"</h1>
|
||||
<p>Hero-scale h1 eyebrows stay with hero-eyebrow-chip; this rule stands down.</p>
|
||||
</section>
|
||||
|
||||
<div class="card-grid" aria-label="Room cards">
|
||||
<article class="suite-card">
|
||||
<span class="taxonomy-label">Suite</span>
|
||||
<h3>"Garden Suite"</h3>
|
||||
<p>Category labels inside sibling cards are metadata for comparison.</p>
|
||||
</article>
|
||||
<article class="suite-card">
|
||||
<span class="taxonomy-label">Suite</span>
|
||||
<h3>"Sea Loft"</h3>
|
||||
<p>The label is useful because the user is scanning sibling cards.</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<ol class="case">
|
||||
<li>
|
||||
<span class="pass-kicker-caps">Step 01</span>
|
||||
<h3>"Step Indicator"</h3>
|
||||
<p>Step indicators in ordered flows are sequence markers.</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="hidden-mockup" aria-hidden="true">
|
||||
<div class="mockup-hero">
|
||||
<span class="taxonomy-label">Amalfi Coast</span>
|
||||
<h2>"Mockup Hero Variant One"</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,263 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Repeated Section Kickers Fixture</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f6f2ec;
|
||||
color: #171411;
|
||||
}
|
||||
main {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 32px;
|
||||
padding: 32px;
|
||||
}
|
||||
.col {
|
||||
min-width: 0;
|
||||
border: 1px solid #c9bfb2;
|
||||
padding: 24px;
|
||||
}
|
||||
.case {
|
||||
min-height: 120px;
|
||||
margin: 0 0 24px;
|
||||
padding: 16px;
|
||||
background: #fffaf3;
|
||||
}
|
||||
.kicker,
|
||||
.pass-kicker {
|
||||
display: block;
|
||||
width: 240px;
|
||||
min-height: 16px;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.11em;
|
||||
color: #5b5046;
|
||||
}
|
||||
.kicker {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 32px;
|
||||
line-height: 38px;
|
||||
font-weight: 700;
|
||||
}
|
||||
p,
|
||||
label,
|
||||
figcaption,
|
||||
a,
|
||||
li {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
nav,
|
||||
form,
|
||||
figure,
|
||||
ol {
|
||||
margin: 0 0 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
min-height: 80px;
|
||||
}
|
||||
.brand-system {
|
||||
min-height: 120px;
|
||||
}
|
||||
.card-grid,
|
||||
.command-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
.suite-card,
|
||||
.command-card {
|
||||
display: block;
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
background: #fff;
|
||||
text-align: left;
|
||||
}
|
||||
.taxonomy-label {
|
||||
display: block;
|
||||
margin: 0 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
letter-spacing: 0.11em;
|
||||
text-transform: uppercase;
|
||||
color: #5b5046;
|
||||
}
|
||||
.suite-card h3,
|
||||
.command-card h3 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.command-carousel,
|
||||
.hidden-mockup {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin: 0 0 24px;
|
||||
}
|
||||
.command-spread,
|
||||
.mockup-hero {
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
border: 1px solid #d8cec0;
|
||||
background: #fff;
|
||||
}
|
||||
.command-spread h3,
|
||||
.mockup-hero h2 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<section class="col" aria-label="Should flag">
|
||||
<h1>Should flag</h1>
|
||||
|
||||
<section class="case">
|
||||
<span class="kicker">Invitation protocol</span>
|
||||
<h2>"The Future Is Admitted"</h2>
|
||||
<p>Repeated tracked labels carry the hierarchy instead of a stronger structure.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<p class="kicker">Preview sequence</p>
|
||||
<h2>"A Private Rehearsal"</h2>
|
||||
<p>The same scaffolding appears again before another section heading.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<div class="kicker">Access window</div>
|
||||
<h2>"Reviewed, Not Sold"</h2>
|
||||
<p>The pattern is now the page's default section grammar.</p>
|
||||
</section>
|
||||
|
||||
<section class="case">
|
||||
<small class="kicker">Material briefing</small>
|
||||
<h2>"Touch the Future"</h2>
|
||||
<p>Four repeated kickers should be enough to flag the page-level smell.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="col" aria-label="Should pass">
|
||||
<h1>Should pass</h1>
|
||||
|
||||
<nav class="case" aria-label="Breadcrumb">
|
||||
<span class="pass-kicker">Home / Journal</span>
|
||||
<h2>"Breadcrumb Before Heading"</h2>
|
||||
<a href="/">Home</a>
|
||||
</nav>
|
||||
|
||||
<form class="case">
|
||||
<label class="pass-kicker" for="guest">Guest name</label>
|
||||
<input id="guest" name="guest" style="width: 220px; height: 40px;">
|
||||
<h2>"Form Heading Is Separate"</h2>
|
||||
</form>
|
||||
|
||||
<ol class="case">
|
||||
<li>
|
||||
<span class="pass-kicker">Step 01</span>
|
||||
<h3>"Step Indicator"</h3>
|
||||
<p>Step indicators in ordered flows should not count as section scaffolding.</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<figure class="case">
|
||||
<span class="pass-kicker">Plate study</span>
|
||||
<figcaption>"Figure Caption Label"</figcaption>
|
||||
</figure>
|
||||
|
||||
<section class="case">
|
||||
<span class="pass-kicker">Lowercase label</span>
|
||||
<h2>"Normal Case Kicker"</h2>
|
||||
<p>Not uppercase, not the repeated AI section-label pattern.</p>
|
||||
</section>
|
||||
|
||||
<section class="case brand-system" data-impeccable-allow-kickers>
|
||||
<span class="pass-kicker">Archive code</span>
|
||||
<h2>"Intentional Brand Label"</h2>
|
||||
<p>Deliberate brand systems can opt out with an explicit marker.</p>
|
||||
</section>
|
||||
|
||||
<div class="card-grid" aria-label="Room cards">
|
||||
<article class="suite-card">
|
||||
<span class="taxonomy-label">Suite</span>
|
||||
<h3>"Garden Suite"</h3>
|
||||
<p>Repeated category labels inside cards are structured metadata, not page-section scaffolding.</p>
|
||||
</article>
|
||||
<article class="suite-card">
|
||||
<span class="taxonomy-label">Suite</span>
|
||||
<h3>"Sea Loft"</h3>
|
||||
<p>The label is useful because the user is scanning sibling cards.</p>
|
||||
</article>
|
||||
<article class="suite-card">
|
||||
<span class="taxonomy-label">Suite</span>
|
||||
<h3>"Cliff Suite"</h3>
|
||||
<p>Repeating it here does not create the generic section-kicker smell.</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="command-grid" aria-label="Command cards">
|
||||
<button type="button" class="command-card">
|
||||
<span class="taxonomy-label">Refine</span>
|
||||
<h3>"/impeccabletypeset"</h3>
|
||||
<p>Command category labels can repeat across many action cards.</p>
|
||||
</button>
|
||||
<button type="button" class="command-card">
|
||||
<span class="taxonomy-label">Refine</span>
|
||||
<h3>"/impeccablelayout"</h3>
|
||||
<p>The repeated taxonomy helps compare tools inside the same group.</p>
|
||||
</button>
|
||||
<button type="button" class="command-card">
|
||||
<span class="taxonomy-label">Refine</span>
|
||||
<h3>"/impeccablecolorize"</h3>
|
||||
<p>This is a card-grid label, not a page-level eyebrow before a section.</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="command-carousel" aria-label="Command carousel">
|
||||
<div class="command-spread" data-category="create">
|
||||
<span class="taxonomy-label">Create</span>
|
||||
<h3>"/impeccablecraft"</h3>
|
||||
<p>Carousel slides can repeat category labels as navigational taxonomy.</p>
|
||||
</div>
|
||||
<div class="command-spread" data-category="evaluate">
|
||||
<span class="taxonomy-label">Evaluate</span>
|
||||
<h3>"/impeccableaudit"</h3>
|
||||
<p>The slash command heading identifies an item, not a page section.</p>
|
||||
</div>
|
||||
<div class="command-spread" data-category="harden">
|
||||
<span class="taxonomy-label">Harden</span>
|
||||
<h3>"/impeccablepolish"</h3>
|
||||
<p>The label is a category chip for a selectable command slide.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hidden-mockup" aria-hidden="true">
|
||||
<div class="mockup-hero">
|
||||
<span class="taxonomy-label">Amalfi Coast</span>
|
||||
<h2>"Mockup Hero Variant One"</h2>
|
||||
</div>
|
||||
<div class="mockup-hero">
|
||||
<span class="taxonomy-label">Amalfi Coast</span>
|
||||
<h2>"Mockup Hero Variant Two"</h2>
|
||||
</div>
|
||||
<div class="mockup-hero">
|
||||
<span class="taxonomy-label">Amalfi Coast</span>
|
||||
<h2>"Mockup Hero Variant Three"</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user