| name | brand-safe-design-pass |
| description | Raise a site's perceived production value with a rigorous UI/UX pass while PROVING no user-facing word changed. Use when the user says "make it look expensive", "premium design pass", "make it feel designed", "rigorous design audit", "improve visual craft", "brand-safe redesign", "polish the UI without changing copy", or "design pass but do not touch the words". ALSO use whenever a visual change is requested on a site whose copy was written or approved by someone else — a client, a lawyer, a clinician, a compliance team — because the real risk there is not ugly CSS, it is a heading getting quietly "improved" during a refactor. Do NOT use for greenfield design (that is a build skill) or for copywriting. |
| version | 1.0.0 |
| category | analyze |
| platforms | ["CLAUDE_CODE"] |
Brand-Safe Design Pass
A design pass on someone else's words. Two jobs, in this order:
- Prove nothing was reworded. Every visible string, aria-label, alt, title
and meta description is snapshotted before the pass and diffed after.
- Raise the craft. Typography, spacing, depth, interaction states.
Job 1 is the point. Any model can restyle a page; the failure mode that burns
trust is a heading that reads slightly differently afterwards and nobody
noticing until the client reads their own site back.
Reordering sections is allowed. Rewording is not. The guard compares a
multiset, so moving a block passes and editing a word fails.
============================================================
=== PRE-FLIGHT ===
Before starting, verify:
If any check fails: say which one and stop. Do NOT audit a dev server, a
login wall, or a page you cannot see. A design report on the wrong pixels is
worse than no report.
============================================================
=== PHASE 1: LOCK THE COPY ===
Copy references/check-copy-integrity.mjs into the project's script
directory, wire two package scripts, and take the baseline:
copy:snapshot -> node scripts/check-copy-integrity.mjs --write
check:copy -> node scripts/check-copy-integrity.mjs
Add .copy-snapshot.json to .gitignore. Run the snapshot. Report the
string count — it is the number you are accountable for at the end.
VALIDATION: .copy-snapshot.json exists and the count is plausible for the
page volume. A suspiciously low count means the gate was not bypassed and you
snapshotted an interstitial.
FALLBACK: if the count looks wrong, fix the bypass and re-snapshot BEFORE any
CSS is touched. A baseline taken after an edit is worthless.
============================================================
=== PHASE 2: CRITIQUE ===
Invoke /design-critique against the running site, both themes if the site
has them. Require file-level evidence for every finding — a critique that
cannot name a file is an opinion.
Then build the factual inventory yourself, because it is cheap and it turns
taste into arithmetic:
grep -rhoE "#[0-9a-fA-F]{3,8}\b" src/ --include="*.css" --include="*.astro" | sort -u | wc -l
grep -rhoE "border-radius:[^;]+;" src/ | sort | uniq -c | sort -rn
grep -rhoE "(padding|margin|gap)[a-z-]*:\s*[^;]*;" src/ | grep -v "var(--" | sort | uniq -c
Healthy: one or two radius values, two or three shadows, almost no untokenized
spacing. A long tail of one-off values is the measurable form of "unconsidered".
Rule out instrument error before reporting anything. Three artifacts have
each produced a confident, wrong finding:
- Blank bands in a full-page screenshot are scroll-driven reveals sitting
at their START state, not missing content. Verify by scrolling each element
into view and re-reading opacity. Report a reveal as broken only if it stays
faded WHILE in view.
- A "near-black" translucent header is your colour parser failing. See
Phase 5.
- SVG text with the wrong colour is you reading
color. SVG text is
painted by fill.
VALIDATION: every finding names a file and a measured number.
FALLBACK: drop any finding you cannot reproduce twice. Shipping a false
positive costs more credibility than missing a real issue.
============================================================
=== PHASE 3: DESIGN INTELLIGENCE, FILTERED ===
Invoke /ui-ux-pro-max for the interaction-state, elevation and spacing lens.
If the project already has a brand guide, REJECT its palette and typography
output. These generators return an industry-average system — a blue and
orange palette with a neutral grotesque — which is precisely the generic look
the user is paying to escape. Adopting it over a real brand guide is the
single worst outcome of this skill.
Keep: state layers, elevation scale, press feedback, stagger timing, tabular
figures, focus rings, target sizes.
Discard: palette, font pairing, and any "recommended pattern" that contradicts
the existing information architecture.
VALIDATION: the brand's own tokens are still the source of truth after this
phase. Diff the token block to confirm it is untouched.
============================================================
=== PHASE 4: IMPLEMENT ===
Fix in this order — cheapest perceptual win first:
- Typography tuned FOR THE FACE IN USE. After any font swap, re-audit the
craft layer. Per-level
letter-spacing written for the old face survives
the swap and silently ruins display type. A sturdy modern with tight
sidebearings wants negative tracking at display size; an old-style serif
with generous sidebearings and a small x-height wants neutral to slightly
positive. Applying the former's values to the latter closes the counters
and reads as cheap without anyone being able to say why. Grep the whole CSS
layer for the OLD font name after any swap: comments, dead selectors and
font-optical-sizing claims all outlive it.
- Line length. Nothing above ~75 characters. Measure, do not eyeball:
width / (fontSize * 0.5). Check the legal and safety text especially —
it is usually in a wide container nobody styled, so the most important
sentence on the site ends up the hardest to read.
- Interaction states that REINFORCE. A hover that removes an affordance
is a bug even when it looks elegant. Underlines should thicken or draw in,
never erase. Animate two background layers so the resting rule never moves
and nothing reflows.
- Depth and press feedback, on transform and opacity only.
VALIDATION: after each fix, re-measure the specific number that was wrong.
FALLBACK: if a fix moves a problem rather than removing it, that is the same
bug in a new place. Keep going.
============================================================
=== PHASE 5: VERIFY ===
Run, in order. All must pass:
check:copy — the whole point. Zero drift.
- axe across all routes and themes, if the project has it.
references/check-contrast.mjs — hover-state contrast. Copy it in and
wire check:contrast.
/mobile-sweep at 360, 390 and 768.
- The project's own gates.
Two things this phase exists to catch, both of which passed every other
gate at the time:
- axe only audits the RESTING page. It never moves the mouse. A
section-level hover rule once painted near-black body text onto a dark green
panel at 1.37:1 while every automated check stayed green. If a dark panel is
nested inside a section, it needs an opt-out class so section hover rules
cannot recolour it.
- Never parse colour strings.
getComputedStyle returns whatever colour
space the CSS produced. A color-mix() header resolves to
oklab(0.95 0.0008 0.0086 / 0.88), and reading numbers out of that reports
a cream header as near-black — 30 false failures in one run. Resolve colour
by PAINTING it to a 1x1 canvas and reading the pixel back, then composite
translucent layers down to the first opaque one. check-contrast.mjs does
this; use it rather than rewriting it.
If /mobile-sweep's bundled script cannot bypass the site's access gate, run
its four checks directly (off-screen overflow, sub-44px targets, clipped
labels, over-wide modals) with the WCAG 2.5.8 exemption for inline links in
prose. Say that you did so and why. Do not report a sweep of an interstitial
as a sweep of the site.
VALIDATION: check:copy passes. If it fails, you changed words. Revert those
specific edits — do not update the snapshot to match.
FALLBACK: a genuinely necessary copy change means stopping and asking. It is
outside this skill's remit.
============================================================
=== SELF-REVIEW ===
Score (1-5):
- Complete: did every phase run, and does
check:copy pass?
- Robust: was each finding measured rather than asserted? Were the three
instrument artifacts ruled out?
- Clean: would the diff read as considered to a designer, with each change
justified by a number?
Below 4 on any axis: name the gap. Fix it if fixable this run, otherwise
report it as a known limitation. Never report a design pass as complete while
the copy guard is failing or unrun.
============================================================
=== LEARNINGS CAPTURE ===
Append one entry to ~/.claude/skills/brand-safe-design-pass/LEARNINGS.md:
## <YYYY-MM-DD> — <project + stack>
- **What worked:** <the change with the biggest perceptual return per line of diff>
- **What was awkward:** <a false positive, a gate that could not be bypassed, a skill whose output had to be rejected>
- **Suggested patch:** <one concrete improvement to these instructions>
- **Verdict:** [Smooth / Minor friction / Major friction]