Add a Refusals page consolidating the system's anti-pattern rules
The Claude Design export for Gloss (chat3, "impeccable.style" pass) audited
the system against a catalog of generated-interface tells and added a
Refusals card. Individual rules already exist scattered across the
foundation pages here (elevation, typography, motion), but there was no
single checklist to audit a new screen against. Adds one as a new top-level
page, registered in lib/build.rb's PAGES list and linked from nav.yml,
rationale.md, and SKILL.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CUag8hbfEiMpyQ9gxxSzv5
diff --git a/SKILL.md b/SKILL.md
index 0e44d1f..932af80 100644
--- a/SKILL.md
+++ b/SKILL.md
@@ -9,7 +9,10 @@ they cover the voice, the visual foundations, and the four hard rules (no
hex or duration outside `tokens.css`, components read aliases not ramps,
every token says what it's for, one accent per project, never two in a
view). `install.md` covers embedding and retheming in more depth than this
-file repeats.
+file repeats. Before shipping a new screen, check it against `refusals.md`
+— the consolidated list of generated-interface tells this system refuses to
+produce (eyebrows over headings, icon tiles above cards, pulsing status
+dots, and the rest).
## Getting the CSS into another project
diff --git a/_data/nav.yml b/_data/nav.yml
index 21c2944..e1a13b2 100644
--- a/_data/nav.yml
+++ b/_data/nav.yml
@@ -3,6 +3,7 @@
- { text: Overview, url: / }
- { text: Rationale, url: /rationale/ }
- { text: Using the CSS, url: /install/ }
+ - { text: Refusals, url: /refusals/ }
- title: Foundations
links:
- { text: Color, url: /foundations/color/ }
diff --git a/lib/build.rb b/lib/build.rb
index 3c26d4c..98feb37 100644
--- a/lib/build.rb
+++ b/lib/build.rb
@@ -67,6 +67,7 @@ PAGES = [
["index.md", "/", nil],
["rationale.md", "/rationale/", nil],
["install.md", "/install/", nil],
+ ["refusals.md", "/refusals/", nil],
*Dir[File.join(ROOT, "_foundations/*.md")].sort.map { |f| [f, "/foundations/#{File.basename(f, ".md")}/", "Foundations"] },
*Dir[File.join(ROOT, "_components/*.md")].sort.map { |f| [f, "/components/#{File.basename(f, ".md")}/", "Components"] },
*Dir[File.join(ROOT, "_patterns/*.md")].sort.map { |f| [f, "/patterns/#{File.basename(f, ".md")}/", "Patterns"] },
diff --git a/rationale.md b/rationale.md
index c733453..eb8fdf4 100644
--- a/rationale.md
+++ b/rationale.md
@@ -150,4 +150,7 @@ Being honest about the design is being honest about the gaps too.
- **Loop and Archive are generic demonstrations**, not real production
screens.
-Naming these is cheaper than being caught by them.
+Naming these is cheaper than being caught by them. For the shapes this
+system actively refuses to reproduce when a new screen is built on top of
+it — kickers, icon tiles over headings, pulsing status dots, and the rest —
+see [Refusals](<%= relative_url('/refusals/') %>).
diff --git a/refusals.md b/refusals.md
new file mode 100644
index 0000000..187586d
--- /dev/null
+++ b/refusals.md
@@ -0,0 +1,80 @@
+---
+title: Refusals
+permalink: /refusals/
+section: Start here
+summary: >-
+ A consolidated checklist of generated-interface tells this system refuses
+ to produce — for auditing a new screen before it ships.
+---
+
+Generated interfaces converge on a small set of shapes: the eyebrow over a
+headline, the icon tile above a card title, the softly-glowing dark theme.
+None of them are accidental omissions here — each is already refused by a
+rule on the relevant foundation page. This page exists only to put all of
+them in one place, so a new screen can be checked against the whole list at
+once instead of five pages in sequence. These are laws, not preferences: a
+screen that breaks one is off-system.
+
+## Surface & elevation
+
+- **No cream or beige page.** The stock is warm but held close to neutral —
+ see [Color](<%= relative_url('/foundations/color/') %>).
+- **No side-accent bar on a card, no four-sided border, no bordered card at
+ all.** [Card](<%= relative_url('/components/card/') %>) is a hairline
+ border plus `--gl-radius-lg`, nothing else.
+- **No hairline border and soft shadow on the same element.** One or the
+ other — see [Elevation](<%= relative_url('/foundations/elevation/') %>).
+- **No decorative grid, stripe field, or radial glow.** Flat color only.
+- **No radius above `--gl-radius-lg` on a card, no custom corner value
+ outside the token scale.** `--gl-radius-full` stays reserved for true
+ pills — [Switch](<%= relative_url('/components/switch/') %>)'s track and
+ thumb, the avatar chip — not a general-purpose corner.
+- **No dark theme with colored glows.** Dark mode repoints the same aliases
+ at the inverted neutral ramp; nothing else changes.
+
+## Type & hierarchy
+
+- **No kicker or eyebrow above a heading.** A heading is already the top of
+ its own hierarchy; stacking a tracked uppercase label over it invents a
+ second, redundant one.
+- **Uppercase and tracking stay on `type-label`.** Never on body copy, never
+ on a heading — see [Typography](<%= relative_url('/foundations/typography/') %>).
+- **No gradient text. No italic serif display headline.**
+- **Adjacent steps in the type scale are 1.2–1.25 apart — not enough
+ contrast on their own.** Skip a step between a heading and the body under
+ it, or the hierarchy reads flat.
+- **A heading gets more space above it than below it.** The gap says what
+ belongs to what.
+
+## Layout & structure
+
+- **No card inside a card.** One level, then spacing and rules do the rest.
+- **A grid of cards is fine when each card is a real, distinct object.**
+ What's refused is the decorative version — identical icon-and-heading
+ cards standing in for a list. Repeated, uniform items belong on a
+ [CardRow](<%= relative_url('/components/card-row/') %>) list, not a card
+ grid.
+- **No icon tile stacked above a heading.** An icon sits beside its label,
+ in flow.
+- **No decorative numbered section labels.** A number appears only when
+ it's real data.
+
+## Motion
+
+- **No pulsing status dot.** Status is [Badge](<%= relative_url('/components/badge/') %>) —
+ tone plus mono uppercase text, on no background. It never animates on its
+ own; only data that's actually changing does — see
+ [Motion](<%= relative_url('/foundations/motion/') %>).
+- **No blinking cursor in non-editable copy, no marquee, no bounce or
+ elastic easing.**
+- **No hover scale on imagery.** Animate `transform` and `opacity`, never
+ `width` or `height`.
+
+## Copy
+
+- **At most two em-dashes in a passage.** Commas, colons, and periods carry
+ the same joins without the cadence.
+- **No "not X, a Y" aphorisms, and no manufactured contrast as a closing
+ line.** State the thing once.
+- **Nothing gets dismissed as "theater."** Say plainly what a thing does or
+ does not do. See the Voice section in `SKILL.md`.