Fix · Manifesto + Sport line-height collision on wrapped uppercase headings

Manifesto and Sport themes set --lh-tight: 0.94 paired with text-transform: uppercase and condensed display faces (Anton / Inter Tight 900). On a two-line .section__title the cap-tops of line N+1 collide with the baseline of line N — most visible on the marketing site's "SAME PROMPT, TWO / DIFFERENT OUTPUTS." headline where the comma and the D fuse into one glyph.

- tokens.css: bump --lh-tight to 1.02 for both themes (safe floor for all-caps condensed display)
- slop-test.md: new gate 67 auto-fails any display-size element that pairs text-transform: uppercase with line-height < 1.0
- typography.md: explicit "Floor for all-caps display heads is 1.0 — recommended 1.02–1.08" line added to body-text rules
- SKILL.md + preview-examples.md: gate count bumped 66 → 67
This commit is contained in:
Youssef
2026-05-18 14:45:40 +01:00
parent 546ddfac86
commit a2cd497977
5 changed files with 19 additions and 11 deletions
+8 -2
View File
@@ -185,7 +185,11 @@
--tracking-tight: -0.02em;
--tracking-label: 0.04em;
--lh-tight: 0.94;
/* Manifesto runs uppercase Anton on display heads — line-height < 1.0 makes
cap-tops of line N+1 collide with the comma / baseline of line N (visible
on multi-line section titles like "SAME PROMPT, TWO / DIFFERENT OUTPUTS").
1.02 is the safe floor for all-caps condensed display. */
--lh-tight: 1.02;
--lh-snug: 1.08;
--section-gap: 5.5rem;
@@ -625,7 +629,9 @@
--tracking-tight: -0.018em;
--tracking-label: 0.10em;
--lh-tight: 0.94;
/* Sport runs uppercase Inter Tight on display heads — same collision risk
as Manifesto when titles wrap to two lines. 1.02 floor for all-caps. */
--lh-tight: 1.02;
--lh-snug: 1.06;
--section-gap: 5.5rem;
+3 -3
View File
@@ -403,7 +403,7 @@ Before emitting any code, output a tight summary of what you're about to ship. T
- **Enrichment** · none (typography only)
- **Sections** · Hero · Logos · Stats · Features · Testimonials · Pricing · FAQ · CTA · Footer
- **Motion** · counter · pricing-lift · pulse-once
- **Slop test** · 66 / 66 ✓ (run after Build)
- **Slop test** · 67 / 67 ✓ (run after Build)
- **Diversification** · differs from Linen on display style + accent hue
```
@@ -414,7 +414,7 @@ Before emitting any code, output a tight summary of what you're about to ship. T
3. **Enrichment** — the chosen archetype + tier, or *none (typography only)*.
4. **Sections** — section names separated by ` · `, in DOM order.
5. **Motion** — microinteraction primitives separated by ` · `, or *none — typography only*. Always under three primitives per the [`microinteractions.md`](references/microinteractions.md) hard rules.
6. **Slop test** — `66 / 66` if all gates pass, or `N / 66 — fails: <gate numbers>` if any are open. Run the slop test BEFORE writing this row; the slop test is Step 7.
6. **Slop test** — `67 / 67` if all gates pass, or `N / 67 — fails: <gate numbers>` if any are open. Run the slop test BEFORE writing this row; the slop test is Step 7.
7. **Diversification** *(optional, only when `.hallmark/log.json` has prior entries)* — what axes differ vs the previous run.
**Then one quiet CTA line, italicised, after the bullets:**
@@ -453,7 +453,7 @@ Always:
### 7. The slop test
Before handing back, run the output through the 66-gate slop test in [`references/slop-test.md`](references/slop-test.md). Every answer must be **no**. Load that file at this step (not earlier — it isn't needed until handoff). The active genre matters: some gates are universal, some are genre-scoped (atmospheric loosens the radial-bloom gate; modern-minimal loosens the zero-chroma neutral gate; etc.). The full per-genre overrides are listed inline in `slop-test.md`.
Before handing back, run the output through the 67-gate slop test in [`references/slop-test.md`](references/slop-test.md). Every answer must be **no**. Load that file at this step (not earlier — it isn't needed until handoff). The active genre matters: some gates are universal, some are genre-scoped (atmospheric loosens the radial-bloom gate; modern-minimal loosens the zero-chroma neutral gate; etc.). The full per-genre overrides are listed inline in `slop-test.md`.
Run the slop test BEFORE writing the Slop test row in the Step 5 preview block — that row reflects the actual outcome of this step.
+4 -4
View File
@@ -12,7 +12,7 @@ Four sample Step 5 preview blocks for the model to imitate, varied across macros
> - **Enrichment** · Tier-B hand-built SVG (a 60-line coffee bean with `@property --rise` 6 s breathing-loop)
> - **Sections** · Masthead · Letter · Three Notes · Visit · Colophon
> - **Motion** · breathing-loop on bean only (respects `prefers-reduced-motion`)
> - **Slop test** · 66 / 66
> - **Slop test** · 67 / 67
> - **Diversification** · first run for this project
*Bento Grid (SaaS, motion-on):*
@@ -23,7 +23,7 @@ Four sample Step 5 preview blocks for the model to imitate, varied across macros
> - **Enrichment** · E1 Clipped-Edge Demo Video, Tier-A CSS-art trace waterfall
> - **Sections** · Hero · 6-tile Bento (stat · sparkline · quote · code · integrations · spotlight) · Index Footer
> - **Motion** · counter · pricing-lift · CSS marquee on integrations strip
> - **Slop test** · 66 / 66
> - **Slop test** · 67 / 67
> - **Diversification** · differs from Plain on paper hue (light-cool vs pure-white) + accent (indigo vs ink-blue)
*Manifesto (declarative, no enrichment):*
@@ -34,7 +34,7 @@ Four sample Step 5 preview blocks for the model to imitate, varied across macros
> - **Enrichment** · none (typography only — voice carries the brand)
> - **Sections** · Masthead · Title · Five Declarations · Bleed Band · What We Refuse · Working Rules · Practice · Reading · Colophon
> - **Motion** · none — typography only
> - **Slop test** · 66 / 66
> - **Slop test** · 67 / 67
> - **Diversification** · differs from Linen on paper band (dark vs light) + display style (display-heavy vs geometric-sans)
*Custom (Coffeebox archival café):*
@@ -45,5 +45,5 @@ Four sample Step 5 preview blocks for the model to imitate, varied across macros
> - **Enrichment** · Tier-A pure-CSS coffee bean (60-line SVG, breathing-loop optional)
> - **Sections** · Masthead · Letter · Three Notes · Visit · Colophon
> - **Motion** · breathing-loop on bean (with reduced-motion fallback)
> - **Slop test** · 66 / 66
> - **Slop test** · 67 / 67
> - **Diversification** · custom axes: light / italic-serif / chromatic-terracotta — differs from previous catalog Linen on accent hue + display style
+3 -1
View File
@@ -192,7 +192,9 @@ Universal. Every emitted page must render flawlessly at 320 px, 375 px, 414 px,
66. **Section eyebrow / tag beside the heading (tag-left, header-right).** Does any section render an eyebrow / number / mono-cap label (`01 · THE TOUR`, `02 / FEATURES`, `Chapter Three`) in a column to the left of, or to the right of, the section heading on the same horizontal row? Auto-fail. The pattern reads as a templated editorial-SaaS tell within seconds. When an eyebrow is used at all (see [`anti-patterns.md § Eyebrow on every section`](anti-patterns.md) — default OFF), the heading goes **directly underneath it in the same column**, vertical stack only. Concretely: any `.section__head`, `.section__intro`, or equivalent wrapper that contains both an eyebrow element and a heading element MUST have `display: block` or `display: flex; flex-direction: column` (or `grid-template-columns: 1fr` with the eyebrow + heading as separate rows). Multi-column section heads with an eyebrow in one column are banned regardless of macrostructure, theme, or viewport. This supersedes the "Left-margin" axis in [`structure.md`](structure.md) and the "Hanging headers" pattern in [`layout-and-space.md`](layout-and-space.md) for any head that carries an eyebrow.
The CSS stamp at Step 6 records mobile pass alongside contrast: `· mobile: pass (36, 59, 6166)`.
67. **All-caps display heads with line-height < 1.0 → cap-collision on wrap.** Does any display-size element (`.hero__display`, `.section__title`, `h1`, `h2`, or anything `≥ --text-2xl`) declare both `text-transform: uppercase` AND a `line-height` (or `--lh-tight`) below `1.0`? If yes, fail. Uppercase glyphs have no descenders and their cap-tops sit at the very top of the line box — at `line-height: 0.94` (the old Manifesto / Sport / Brutal default) the cap-tops of line N+1 visibly collide with the baseline or commas of line N when the title wraps. The condensed display faces (Anton, Inter Tight 900, Bebas Neue) make this worse. **Floor for all-caps display heads is `line-height: 1.0`; recommended `1.021.08`.** Either bump `--lh-tight` ≥ 1.0 for the theme, or drop `text-transform: uppercase` on the display element. Most visible when a two-line `.section__title` wraps with a trailing comma on line one ("SAME PROMPT, TWO / DIFFERENT OUTPUTS.") — the comma + cap-D fuse into a single glyph blob.
The CSS stamp at Step 6 records mobile pass alongside contrast: `· mobile: pass (36, 59, 6167)`.
---
+1 -1
View File
@@ -221,7 +221,7 @@ Use no more than five sizes on a single page. If you need more hierarchy, use we
## Body text rules
- Minimum 16px. Below 14px is accessibility-hostile.
- Line-height 1.51.65 on body copy, tighter (1.11.3) on display.
- Line-height 1.51.65 on body copy, tighter (1.11.3) on display. **Floor for all-caps display heads (`text-transform: uppercase` on `.hero__display` / `.section__title` / `h1` / `h2`) is `1.0` — recommended `1.021.08`.** Below 1.0 the cap-tops of line N+1 collide with the baseline of line N (no descenders to cushion the gap); the comma + cap-D on a wrapped "PROMPT, / DIFFERENT" fuse into a single glyph blob. Condensed display faces (Anton, Inter Tight 900, Bebas Neue) make this worse. Gate 67 auto-fails the pattern.
- Measure 4575 characters (`max-width: 65ch`).
- Never all-caps body copy. Never justified text without hyphenation. Never letter-spacing above 0.05em on body.