117 Commits
Author SHA1 Message Date
Youssef 5939dd9e25 The work list stops folding its descriptions into the numeral column
.work is a two-column grid holding three items: the counter, the name, and the
description. With no placement the description auto-flowed into row 2 column 1,
so every project blurb rendered 96px wide and wrapped to seven lines. Pinning it
to column 2 puts it under the name where it belongs.

The row gap was a second bug hiding behind the first. .work__name already
declares an 8px bottom margin for exactly this pair, but the grid's 32px gap
stacked on top of it, so the two spacing systems fought and the name sat 40px
above its own description. The gap is now column-only, in both the base rule and
the narrow-viewport override, and the margin the author wrote is the one that
governs.

Checked at 1280px and 375px: name and description share a left edge, 8px apart,
no horizontal overflow. Still 0 FAIL.
2026-08-06 11:15:04 +01:00
Youssef ea271b7db5 Derivation becomes the default, and nine themes get faces the model would not have reached for
Every build now derives its own visual world. Silence used to route to the
catalog; it routes to the ritual instead, and the 24 themes become a fast path
you ask for by name, by --fast, by an existing design.md, or by component scope.
custom-theme.md is promoted and renamed to direction.md, trimmed from 336 lines
to 258, and the draw runs on every build rather than on a branch that almost
never fired.

Nine themes prescribed a display face that is a training-data default, one of
them (Source Serif, on Field) already on our own ban list. All nine are re-faced:
Specimen to Bodoni Moda, Studio to Erode, Atelier to Sentient, Newsprint to Zilla
Slab over Spectral, Sport to Saira Condensed, Editorial to Bricolage Grotesque
over EB Garamond, Cobalt to Familjen Grotesk, Hum to Chillax, Field to Literata.
Atelier moving off a Didone also settles the Specimen collision the rejection
table had been arbitrating by hand. The catalog keeps the saturated faces but
now says plainly that they are the first answer, and treats them the way R.2
treats any spent default.

Repairs the flip exposed. Gate 57 tested for the presence of a catalog name, so
a derived build stamped theme: custom and sailed past the exact failure the gate
exists to catch; it now tests the absence of studied-DNA. macrostructures.md
still ordered you to pick a shape before writing code. Colour posture was scoped
to custom builds only. Two gate exceptions in the playful genre were scoped to a
theme name that a derived build cannot claim, and are now scoped to the declared
property.

The tier map had a worse bug than any of those. Thirteen gates carry a Floor
clause and a Reflex clause under one number, and the linter held one tier per
number, so six Floor clauses were quietly waivable and seven Reflex clauses were
quietly unwaivable. tierOf() now resolves the exact clause first, and gates 7,
24, 38a, 47 and 55 emit the clause they actually found. Gate 47 was also
reporting WARN for a Floor violation that reads "fail, always".

That surfaced real defects in the corpus: seven italic emphasis words inside
roman headlines, the top AI tell, sitting in our own showcase pages. They are
now roman accent spans. Two improvised absolutes in the contact sheet use the
token that was already declared beside them. The study verb's output page had
six hand-written numerals above headings, missed by the eyebrow sweep; the list
is a real ol with a counter now.

Corpus: 56 findings down to 41, zero gate 54, Floor enforced honestly.
Read-set cost of the flip: +303 lines a run (+19.3%), down from +400 (+25.4%).
That is short of the +200 target and I am not closing the gap by gutting the
palette construction or the font guidance, which is where the remaining weight
sits and what makes a derived run worth taking.
2026-08-06 11:12:28 +01:00
Youssef 5b4bf7e443 Reflex gets its own grade, the Floor gets a second door, and the shots are true again
Four things the last pass left open.

Reflex findings no longer masquerade as Floor failures. They report at a new
REFLEX grade which still blocks, so nothing drifts silently, but "0 FAIL" is now
a true statement about the floor even while a build owes an argument above it.
Across every committed page that distinction turns 230 reported failures into 56
real Floor findings and 174 arguable ones, which is the number that was hiding.

The waiver cap is gone. Three-per-artifact was the restraint the tier existed to
remove: a colour-field poster that wants a black stage, achromatic neutrals, a
long measure and one face doing everything is right, and it was being blocked for
being expressive. Guards, reason quality and the log are what keep waivers honest.
Past three the build gets a NOTE saying what it now is, a house style rather than
a set of exceptions, and pointing at design.md.

The Floor has two admission criteria instead of one embarrassed exception. Door 1
is "no admired page breaks this on purpose". Door 2 is a named house rule where
admired pages do break it but a language model reaches for it unprompted on every
section. Gate 54 is the only member, listed in a table that any future addition
has to join explicitly. The apology is gone; the reasoning is in the file.

Finish findings gained a record form. `answered <check> · <reason>` parses, so a
build that reasons its way past gate 38 leaves something the next run can read
instead of prose in a comment.

Also: the skill stops mandating em and en dashes in page copy, which had it
arguing with its own house rule. The Picks block and the Step 5 preview merge into
one recital, since the same decisions were being serialised four times. The font
catalog and the per-tone voice samples become skip-unless-needed, roughly 200
lines a build. Two waiver bugs found by a cold build are fixed: "intentional
design choice" was passing the boilerplate test, and a malformed two-field waiver
was being ignored in silence.

The 18 hero captures and 14 gallery thumbnails are regenerated against the live
pages, so the README and the homepage stop advertising eyebrows the skill bans.
2026-08-03 13:27:37 +01:00
Youssef 869d6be23e The floor holds the mechanics; it never picks the direction
Hallmark was telling good models what to build. This splits it into a floor
that binds and a library that offers, and bans the eyebrow outright.

The eyebrow. Gate 54 goes from geometry to existence: short inert type before a
heading that announces it is banned in every arrangement, and no brief earns it
back. The detector inverts from CSS-first to DOM-first, so it now sees flex and
block stacks, heads declared inside a media query, class-less headings, and the
word "overline". Small type before a heading survives only when it carries a
fact, a destination, or an identifier, which keeps captions, field labels,
datelines, unit labels and linked chips legal. references/section-entry.md is the
replacement: twelve ways into a section, ten of them pointing at material the
skill already had.

Themes stay themes. A written contract in theme-axes.md says a theme carries
material and never a page plan, and all 24 are trimmed to it: 4,070 lines down to
2,861. Lumen loses a mandatory hero apparatus and a fixed section sequence; hum
loses 45 lines of global layout rules filed under a theme. Fake brands, invented
people and shippable taglines come out. Genre files stop mandating nav and footer
archetypes they disagreed with the themes about.

Tiers. All 58 gates gain one: 34 carry a Floor clause nothing ships through, 18
are Reflex gates a build with an argument can waive on the record, 6 never block.
Fifteen gates split so a real floor stops dragging a taste threshold behind it.
Gates 42 and 43 stop ordering a rotation through the catalog and instead ask that
the default be named rather than defaulted into. A waiver declares itself in the
stamp with guard evidence the linter re-derives; three per artifact, one per
gate, Floor never waivable, and an over-cap waiver lets its gate fire so waiving
twelve is worse than waiving none.

The catalogs stop being a mandatory pick. Step 2 asks for a designed page shape
stated in plain words; the named shapes are there when a starting point helps.
Anti-repetition moves from "rotate the codes" to "differ from your last three and
say how", which constrains sameness without constraining invention.

Contradictions. Display line-height had three ranges and now has one owner. The
outlier face was capped at two slots by one line and uncapped by the next. Gate
39 hard-coded 44px against finish.md's 32-40px allowance. Gate 14 banned padding
animation that floating-nav.md prescribes. Gate 57's theme list had drifted to 20
of 24. F3 and gate 51 fought over overflow-wrap; break-word settles it.

Evidence. 201 eyebrows removed across 38 example pages and 32 across the archived
test builds, each replaced with a real opening rather than deleted; aggregate
failures fell while doing it. The marketing site drops its own section labels and
moves hero labels below the lede. A cold build through the revised skill lands
0 FAIL / 0 WARN, names its own structure instead of picking a code, and argues
with a Reflex gate rather than waiving it.
2026-07-31 17:43:28 +01:00
Youssef 1695c9defb Trim the branch to what the README and the site actually show
The eval run outputs, the internal design proposals, and a scratch QC
page for the imagery kit were all riding along in the PR while being
linked from nothing. They come out of tracking: eval/runs (the four A/B
cells from this session plus the older model-comparison artifacts, all
of it evidence rather than product), site/_proposals (44 files of
before/after and theme-exploration pages, preserved outside the repo),
and site/imagery/_qc.html (a scratch grid I used to eyeball the
generated assets). The eval harness itself stays so the tests are
re-runnable, and .gitignore now covers the pycache and the QC pages that
slipped past it.

The four theme examples added this round stay: arcade-01, field-01,
grid-01, and ledger-01 are the worked examples their own theme docs link
to, not stray test output.
2026-07-31 14:25:25 +01:00
Youssef 94ae30e680 The imagery kit is real: 39 committed assets, a filled manifest, no more fake people
site/imagery/ now ships (serving at usehallmark.com/imagery/ on deploy):
16 photoreal placeholder avatars (768px, varied ages/skin/hair on neutral
studio grounds, natural texture, no smooth-mesh AI look; provenance JSON
sidecars committed; each paired deterministically with a unisex name so
gate 19 never meets another Jane Doe), 4 watercolor washes and 4 single-
colour brush gestures on white ground (composited via multiply - no faked
alpha; the category skips dark themes), 4 hand-built tileable texture
SVGs, 12 hand-built currentColor marks in four geometric families (inline
them - img cannot inherit currentColor; wordmarks are a composition of
mark + display-token text, since baked-text SVGs cannot use page fonts),
and 3 app-screen frames built on Hallmark tokens with their HTML sources
committed beside them for one-command re-render. Total 1.7MB, ~$1.06 of
Together spend, every generated file QC'd in the browser (two off-brief
brushes were regenerated single-colour and pixel-verified).

imagery-kit.md's manifest is now the real allowlist with provenance
columns; the categories table gains avatar/mark/screens rows and the
white-ground multiply contract; the placeholder ladder's tier 1 points at
the real kit and tier 4 loses person keywords (F9's territory); the
portrait row of the image-need table routes to kit avatars.
2026-07-31 12:35:47 +01:00
Youssef de3a01dd84 Gate 23 gets teeth: one accent number, measured two ways
color.md's 3%-vs-5% contradiction resolves to 5% everywhere. The gate
moves from judged-only to M/R:

- static half (sloplint.mjs check23, WARN-grade): flags accent tokens
  painting viewport-scale rules (body/section/hero-class selectors, or
  rules sized >= 40dvh / 320px / inset 0) and display-size accent text.
  Posture-aware via the stamp comment (Drenched skips; Committed and
  dark papers are structurally exempt because fields and papers are
  never accent tokens); alpha-thinned washes and atmospheric radial
  blooms pass
- render half (sloplint-render.mjs, 1280x800 only, undeclared-posture
  pages): resolves the accent tokens to sRGB and sums painted area on a
  16px union grid (no double-counting of nested rects); > 8% FAIL,
  > 5% WARN, atmospheric thresholds 30/20. Along the way the render
  tier gains a real colour parser: modern Chrome serializes computed
  values and canvas fillStyle in their authored space, so oklch is now
  converted with the same math sloplint uses (the old rgb-only regex
  would have silently skipped every oklch page)

Verified in the browser: a full-bleed accent fixture measures 94.2%
painted (FAIL) and the live coral landing measures 0% (pass); the static
half flags the fixture's three sites and stays quiet on all canonical
examples. Also: garden-01's pre-existing zero-chroma mask-matte token
gains 0.005 chroma so the full example sweep is 0-FAIL again.
2026-07-30 16:35:35 +01:00
Youssef 886e1669db Catalog de-duplication: axis twins broken, mid paper band opened, fingerprints complete
- Coral: General Sans becomes the display/body family (Geist falls back);
  axis moves to grotesk-sans, breaking the Bloom/Coral twin
- Aurora: the teal-green (172) is promoted to the one UI signal at
  oklch(68% .145 172) (7.7:1 on paper) and cyan demotes to the first bloom;
  display becomes Sora 600. Breaks the Midnight/Aurora twin and cuts the
  Geist display collision from four themes to two
- Almanac 94% -> 84% cool slate stock and Riso 91% -> 84% pink stock: the
  previously empty mid paper band gets its first two occupants. Muted greys
  darkened to hold 4.5:1+, Riso's spot blue deepened to oklch(46% .14 220)
  so focus rings stay >= 3:1 on the deeper stock (the old cyan was already
  under 3:1), both accent-ink slots fixed to = paper (were unreadable)
- structure.md fingerprint table now covers all 24 themes; Aurora's row no
  longer duplicates Bloom's, the Brutal/Manifesto identical-row twin and
  the Sport/Coral/Bloom/Studio/Terminal near-twins are re-grounded, and a
  mechanical pairwise check passes: no two rows share more than three of
  the six structural axes (noted in the table preamble)
- theme-axes rows + closing note (Aurora 172 vs Ledger 185 arbitration),
  four spec files rewritten to the new values, main.js theme copy synced
  (plus the stale riso proofA and coral three-percent lines), site font
  links gain Sora + a Fontshare link (also fixes Sentient never loading),
  theme dots updated. Verified in the browser: riso/almanac render on the
  new stocks, Sora/Sentient/General Sans all load
2026-07-30 16:22:45 +01:00
Youssef de6d5a4903 One release: everything on this branch is v1.2
Unify every version string: skill frontmatter and preview block, package.json,
the four preview-examples samples, the eval direction note, the ROADMAP opener,
and the site badges/captions (which were still stamped v1.1/v1.3). The PR is
retitled to match and sits as a draft on the renamed v1.2 branch.
2026-07-30 16:08:57 +01:00
Youssef 746e812d90 Variants corner dock: full-bleed pages, one control surface bottom-right
The picker's single view, the on-page chip, the injection overlay, and the
static compare page all wrapped or barred the page they were showing. Replace
all four chromes with one shared HmDock factory in core.mjs: a compact glass
bar pinned to the bottom-right corner (grid glyph, chevrons, direct number
jump with a dimmed pulse for still-generating directions, small-caps title,
Pick, and an expandable tray with tuple meta, Riff, Graft, and key hints).
The page itself now fills the viewport everywhere.

- chip/inject mount the dock in a shadow root so page CSS cannot touch it,
  and read /api/state to learn titles, meta, and the live direction count,
  so a riffed direction 4 is reachable even with a stale data-of (serve.mjs
  gains CORS on /api/state for the routes-mode cross-origin read)
- chip gains Graft parity and an optional data-title attribute
- single view cycles ready directions only; compare page swaps the fake Pick
  for an honest 'pick N' chip that copies the chat reply to the clipboard
- variants.md updated to the dock (chip contract, picker walkthrough, riff
  note, static-compare shape, poll-ladder wording); site demo mirrors it

Verified in the browser on a scratch run: grid, full-bleed single view,
tray, ready-only arrow cycling, pick queued and drained through await.mjs,
chip on a direct page, live count refresh, static compare, mobile.
2026-07-30 12:08:33 +01:00
Youssef 3093e9e2f8 Fix grid-01 example: zero-chroma neutrals violated gate 22
The example was ported from the proposal mockup with oklch(x% 0 0) neutrals;
the shipped Grid theme tokens carry a faint cool cast (0.003-0.010 at hue 255).
Bring the example's palette in line: 7 FAILs -> sloplint clean.
2026-07-30 12:08:20 +01:00
Youssef 3968b6264c Coherence pass: fix the five defects the v1.3 review surfaced
- main.js: 4 stray '57 gates' marketing strings -> 58
- all-themes.html: visible H1 '20 themes' -> '24 themes'
- gen-cli.mjs header: correct arm ids (claude/glm/kimi) + token env names
  (ZAI_AUTH_TOKEN / MOONSHOT_AUTH_TOKEN)
- ledger spec: radius claim '8px tight' -> '12px card / 8px controls'
- arcade spec: note the starfield/scanline vars are page-local decorative
  tokens (define in :root per arcade-01), not catalog tokens
- tier-e stamp example uses the real imagegen default; hyphens
2026-07-24 15:08:01 +01:00
Youssef cc06e7f23c Variants v2: speed (progressive, sketch-default, parallel, analysis-once) + smoothness (grafts, section-zoom, decisions) + thumbnails + scoped injection
- scripts: core.mjs picker gains PNG-thumbnail grid (falls back to the
  scaled iframe), a Graft button + G key; serve.mjs adds /thumb + /inject
  routes and a graft action on /api/pick; new thumbs.mjs (dual-engine,
  zero-install); buildInjectJs for dev-only Vite/Astro/SvelteKit preview
  injection. All v1 behavior preserved (smoke-tested end to end + browser).
- verbs/variants.md v2 (280->423): progressive-first flow, parallel default
  + analysis-once + shared head, sketch-depth drafts by default (--full),
  optional --fast-drafts, compositional grafts, section-zoom after the pick,
  decisions.md log, thumbnail step, Vite/Astro/SvelteKit injection recipes.
- eval/variants-bench.{md,mjs}: speed-bench doc + a mechanical timing harness.
- site/_proposals/variants-demo.html: client-only progressive-picker demo
  (gradient text removed to stay on-brand); variants-vs.md head-to-head.

Verified in the browser: progressive fill (building -> thumbnail), labeled
counter, guarded arrows, Pick/Riff/Graft, live single-view iframe.
2026-07-24 14:53:59 +01:00
Youssef f760298ca9 Image hook (Together) + canonical examples for the 4 new themes
- scripts/imagegen.mjs: opt-in generated-still hook via Together's images
  endpoint (FLUX.1.1-pro default, gemini-3-pro-image optional), cache by
  prompt hash, provenance sidecar. No key -> graceful exit 3, falls back
  to CSS-art / placeholder (verified). Wired into tier-e-generated.md +
  SKILL Step 4 as opt-in, never auto-fires.
- site/examples/{grid,field,ledger,arcade}-01: canonical builds from the
  proposal mockups, all sloplint 0-FAIL, referenced by each theme spec.
2026-07-24 14:33:25 +01:00
Youssef 5426348836 Wire 4 new themes into the catalog: Grid, Field, Ledger, Arcade (20 -> 24)
- tokens.css: 4 [data-theme] blocks (full token set; Grid neutrals tinted
  to pass gate 22; Ledger/Arcade color-scheme dark; Arcade second accent)
- main.js: THEMES / ARCHETYPES / THEME_GENRES / COPY entries for all 4
- theme-axes.md: 4 rotation rows; SKILL.md Step 2.6 cluster list; genre
  files (Grid->editorial, Ledger->modern-minimal, Field+Arcade->playful)
- count strings bumped 20 -> 24 across skill, site, README; stale 57->58
  gate counts fixed in marketing copy
- Arcade gate-47 carve-out in slop-test + anti-patterns (pixel/scanline
  allowed; fake OS chrome still banned)
- site loads the 4 new themes' fonts; all 24 render in the live picker
2026-07-24 14:29:47 +01:00
Youssef 75bafe3188 Strip em/en dashes from theme demo files 2026-07-24 10:38:05 +01:00
Youssef 054a860224 Seven full-page theme mockups: Plate, Grid, Bench, Maison, Field, Ledger, Arcade
Each is a complete self-contained landing page for a fictional brand in
the candidate theme's tokens, grounded in the reference sites (Aesop,
Vitra, Teenage Engineering, The Row, Notion, Mercury, Panic). All seven
pass sloplint clean (0 FAIL, 0 WARN). Linked from the theme cards via the
Open-full-page overlay.
2026-07-24 10:37:32 +01:00
Youssef 3e6fe26e73 Proposal pages: clickable full-page views + generated-page browser
- five-themes cards open a complete full-page mockup per theme
- before/after cards open the actual generated pages (before from
  hallmark-lab, after from the eval runs), copied into _proposals/pages
- eval judge defaults to operator mode: no Anthropic key spend, the
  Claude Code operator scores from the screenshots; --provider together
  or anthropic for an automated pass
2026-07-24 10:17:20 +01:00
Youssef 01386239f3 Eval run 2026-07-23: findings, judge fallback chain, output-ceiling fix
Full-pack matrix on Claude, GLM (Together), and the Kimi stand-in:
zero mechanical FAILs everywhere after at most one repair round; the
floor-only pack collapses on open models (96 FAILs on GLM), so the full
skill is load-bearing, not bloat. No-vision probe: every model declined
cleanly. Zero invented metrics. Rotation held per arm.

judge.py: Together vision fallback chain + User-Agent fix; vision judge
itself pending API credit or an OpenRouter key. gen-direct: 64K output
ceiling (Claude needed 37K on one brief).
2026-07-23 14:41:11 +01:00
Youssef 6d52d29c50 Coherence pass: fix every contradiction the five-walkthrough review surfaced
- one canonical top-of-file order: stamp, critique line, direction contract
- theme-axes.md: the 20-row Rotation lookup now ships inside the skill
- tier taxonomies unified by name; craft tiers keep construction letters
- S1 reworked to stacked-numbered (the old side-column head was gate 54's
  own auto-fail); carnival + lumen examples brought up to gates 54/55/24;
  sloplint: mask/filter exemption on gate 22, precision fix + FAIL grade
  on gate 54, 15-line stamp window
- variants playbook matches the scripts byte for byte (request ids, riff
  shape, fallback wording, flow order); draft-sweep exceptions written
  into slop-test, custom-theme, and SKILL
- study.md: italic roles diagnosed as-is, built roman; preview-examples
  regenerated for v1.2
2026-07-23 13:28:26 +01:00
Youssef 80701e3cc5 Speed pass: consolidate SKILL.md, slim anti-patterns, split enrichment and craft into index-then-pick files
- SKILL.md 559 to 331 lines: critical floor, flow skeleton, one Rotation
  block, one Picks block, fast mode, per-step Do lines
- anti-patterns.md becomes a 120-line pre-emit list; audit reporting
  moves to verbs/audit.md
- hero-enrichment.md and custom-craft.md become slim indexes over new
  references/enrichment/ and references/craft/ per-pick files
- Core-15 sweep named in slop-test.md for component scope
- pointer cleanup in macrostructures.md and component-cookbook.md;
  tokens.css header count fixed
2026-07-23 12:40:42 +01:00
Youssef 0c4f5ef8d3 Theme research: proposal page with five candidates and two alternates 2026-07-23 12:40:42 +01:00
Youssef 02a3a1dfad New OG image and a refreshed README example gallery
Swapped in the new Open Graph image (2400x1260), keeping the OG-hallmark.png
filename so the meta tags, the README banner, and the deployed URL all stay
valid; updated the height meta to match.

Refreshed the "Different briefs, different shapes" gallery to the worked
examples we actually ship now: the four new themes (Bubble, Distil, Cold Snap,
Cinder), the Custom and newly generated pages (Mend Assembly, Hollowback Apiary,
Off-Register, Press Quaternary), and four originals (Tally, Wayfare, NAJM,
Hyperlane). Dropped the retired examples, reworded the intro, and added eight
new hero shots.
2026-06-03 17:02:02 +01:00
Youssef ae2f83e55d Lead with Hum, fix theme-picker number contrast, reorder worked examples
Theme picker: Hum is now theme 01, with the rest renumbered 02-20. The ordinal
reads off the registry index, so switching, cycling, and the "NN / 20" readout
all stay correct.

Theme numbers: each picker swatch now carries an explicit number colour that
contrasts with its own background, instead of inheriting the active theme's ink.
Dark swatches (Midnight, Terminal, Manifesto, Aurora, Lumen) get a light number
rather than a near-invisible dark one. All twenty clear AA (min 10:1).

Worked Examples: moved the first three carousel cards (Cobalt, Carnival, Lumen)
to the end so the page leads with Hum.

Bumped the asset cache-bust.
2026-06-03 16:19:09 +01:00
Youssef 7a890a365d Carnival rework, sharper anti-slop guards, and three new worked examples
Carnival: fixed the three palette drops whose second accent failed contrast,
tightened the display tracking, and added section-rhythm, alignment, and
drop-selection guidance so the theme lands well-aligned and readable by
default. Lightened and tightened the Carnival headers on the landing.

Anti-slop guards (skill references): heading-to-body alignment coherence as a
principle rather than a rigid rule; centered overlays and command palettes must
center via their container; and a hero headline is never only a number, a lead
figure always pairs with words.

Worked Examples: added three generated pages to the landing carousel, a
small-batch honey farm, a risograph print fair, and an experimental type
studio, after fixing their nav centering and section alignment.

Media: removed the Soroe example card along with the unused scroll-videos,
poster stills, and orphaned thumbnails it left behind, and bumped the asset
cache-bust so the restyled CSS reloads.
2026-06-03 15:27:32 +01:00
Youssef 72f3dc052e Worked examples: full-page image hover-scroll on every card; bump to v1.1
Replace the carousel's inconsistent scroll-videos with one CSS image hover-scroll
across all twelve cards. Each thumb is a tall full-page screenshot that pans top
to bottom on hover, with a per-card duration scaled to page height so they all
move at the same brisk, readable pace; captured Retina-sharp at 1400px wide.
Touch and reduced-motion get a static crop. Drop the Slow Pour card.

Bump the version to v1.1 on the landing (banner + footer), package.json, SKILL.md,
and the preview-block examples.
2026-06-02 20:20:23 +01:00
Youssef 7d870f70ec Worked examples: scroll-on-hover for the new cards, plus README + link polish
Give the five image cards (the four new themes and the Mend Assembly) a
hover-scroll: each thumb is now a tall full-page screenshot, and CSS pans
object-position top to bottom on hover so the page scrolls itself. No video,
no JS, GPU-light; touch and reduced-motion get a static top crop. Cache-bust
the regenerated thumbs.

Trim the README Custom section to the single Mend Assembly feature (matching
the landing) and de-dash the whole README. Fix three pre-existing dead doc
links in the component cookbook (floating-nav, custom-craft, hero-enrichment
were linked without the ../ that reaches the references root).
2026-06-02 19:16:07 +01:00
Youssef 455c2654bd Worked examples: feature Bubble for Hum and trim the custom showcase
Swap the Hum carousel card from Sprout (hum-02) to Bubble (hum-07), the
guided sourdough Narrative Workflow build. Keep only one custom example in
the showcase, the Mend Assembly repair-cafe poster; the other bespoke pages
stay in the repo but off the landing. Untrack hum-02 so only featured builds
ship, refresh the scroll-demos manifest, and bump the cache version.
2026-06-02 18:54:33 +01:00
Youssef a5593bbca1 Slop test · consolidate 70 gates → 57 (merge redundant) and resync every reference
Merge the clear duplicates (gradient text into the gradient gate, macrostructure-
repeat into the structural-fingerprint gate, the overflow-x:clip mandate into the
horizontal-scroll gate, emoji-icon into the icon-libraries gate), collapse the five
contrast gates to two, the five input-state gates to one, and the four hero gates to
two. No coverage lost. Renumber 1–57 and update every gate-number and gate-total
reference across SKILL.md, the reference docs, the landing copy, and the example builds.
2026-06-02 18:34:47 +01:00
Youssef 31f58c56df Hum · lead the default hero with "Make your AI agent a designer." 2026-06-02 18:08:44 +01:00
Youssef bd9e9ab859 v1.1 — four new themes, the Custom route, and a full copy pass
Adds Carnival, Lumen, Hum, and Cobalt to the catalogue (now 20 themes),
each with its own tokens block, hero archetype, landing copy, and spec doc.

Introduces Custom as a first-class route: when a brief carries real
creative intent, Hallmark designs the whole page from first principles —
palette, type, and structure — rather than recolouring a catalogue theme.
Ships five worked custom examples and a README section.

Rewrites the per-theme landing copy and reconciles every catalogue count
across the site and the skill (20 themes · 21 macrostructures · 50
component archetypes · 70 slop-test gates). Drops the last competitor
references from the CSS comments, fixes the genre rosters, and ignores
the local example explorations so only the featured builds ship.
2026-06-02 17:50:31 +01:00
Youssef 3ec0173896 Install · scope the skill to skills/hallmark/ (fixes #9)
The skills CLI copies everything under the directory containing SKILL.md.
With SKILL.md at the repo root, installs were pulling in docs/, site/,
package.json, README, ROADMAP, vercel.json, LICENSE. Moving the skill
into skills/hallmark/ scopes the install to just SKILL.md + references/.

The CLI's priority search hits skills/ first, so `npx skills add
nutlope/hallmark` is unchanged. Updated README install paths,
package.json (entry/references/files), and the internal links that
crossed the new boundary.
2026-05-26 12:07:51 +01:00
Youssef 9fc2369e09 OG · swap to new readme/social card art
New 2400×1356 artwork replaces the previous 4800×2520 image.
Meta width/height tags updated to match.
2026-05-20 16:26:02 +01:00
Youssef a0a02cae7f Study · drop the refuse-competitor-pages clause
Remove the "refuses competitor pages" policy from the study verb.
Touches the verb summary in README and SKILL.md, both refusal tables
in study.md, the URL refuse list, the schema's refusal enum, the
emission-attestation parenthetical, and the worked examples plus the
test fixtures.

Paid-template refusal and the signature-work soft-refusal stay —
those carry real copyright weight.
2026-05-20 14:40:52 +01:00
Youssef fc38eb7a80 Site · add Plausible analytics snippet to head 2026-05-19 19:49:36 +01:00
Youssef 4051c22776 Codex · trim SKILL.md description under 1024-char limit + document install path
Codex enforces a 1024-char cap on the frontmatter description; ours was 1813,
causing "invalid description: exceeds maximum length of 1024 characters" on
load. Rewrote to 927 chars, lossless on routing signals — all five fire
triggers, all three don't-fire conditions, and the decisive heuristic are
preserved. Stripped duplicate verb listings, parenthetical examples on each
trigger, and padding prose.

README + site install panes now document `~/.codex/skills/hallmark/` (personal)
and `.codex/skills/hallmark/` (project-scoped) for Codex, replacing the prior
"manual / git clone" placeholder.
2026-05-19 19:43:21 +01:00
Youssef 38f1885c97 Site · tighten banner picker↔shuffle gap to match Install↔Star + link "Together AI" in footer 2026-05-19 19:08:44 +01:00
Youssef 0757b51936 Fix · star counter shows live count + stale-while-revalidate 2026-05-19 18:51:58 +01:00
Youssef 9f9cf0dbd5 Site · point at www.usehallmark.com + fade page in once web fonts resolve 2026-05-19 16:07:34 +01:00
Youssef 899d846196 Fix · escape YAML-breaking colon in SKILL.md frontmatter + gitignore ephemera
The skills CLI's frontmatter parser rejected SKILL.md with "Nested mappings are not allowed in compact mappings" because the description contained " ANY of: (1) " — the colon-space sequence inside an unquoted YAML scalar made the parser think it had hit a nested key/value pair. End result: 'npx skills add nutlope/hallmark' cloned successfully but then bailed with "No skills found. Skills require a SKILL.md with name and description."

Fix: rephrase "Fires when ANY of:" → "Fires when ANY of these match —". Single character semantic — colon→em-dash. Frontmatter now parses cleanly under js-yaml. No content semantics change.

Also tightened the repo to what actually helps the skill or a future user — per the new instruction. Added to .gitignore + git rm --cached:
- .hallmark/                — runtime state from my dogfooding runs, has no business being committed
- site/_launch-comparison/  — one-off launch-day comparison artifact (Hallmark / Impeccable / no-skills); not linked from the marketing site, README, or anywhere else

Working-directory copies preserved (rm --cached, not rm). docs/talk-slides.md left in place — it's user-authored content, not mine to remove.
2026-05-19 12:18:24 +01:00
Youssef aedca8cb03 Refactor · move SKILL.md + references/ to repo root so 'npx skills add nutlope/hallmark' works
The published install command in the README — npx skills add nutlope/hallmark — was failing for users because the skills CLI looks for SKILL.md at the repo root, not at skill/SKILL.md where Hallmark kept it. The clone succeeded but the CLI reported "No skills found." Manual cp was the only working install path.

Flattened the layout:
- skill/SKILL.md            → SKILL.md
- skill/references/         → references/
- (skill/ directory removed; was empty after moves)

git mv preserved rename history for all 76+ files (SKILL.md + 28 reference files + 21 macrostructures + 46 components + 7 verb/genre subfolders).

Updated every cross-reference (36 occurrences across 9 files):
- README.md — 4 links (SKILL.md + references/ + the install snippet still reads the same)
- ROADMAP.md — 4 links to reference files
- package.json — "files" field + "skill" entry/references paths
- site/js/main.js — 3 source comments
- references/design-md.md — one broken link (was pointing skill/references/export-formats.md from inside references/ — now just export-formats.md as a sibling)
- site/_tests/verbs/study/notes.md, diagnosis.md and verbs/audit/audit-report.md, custom/README.md — test-artifact relative paths shortened by one segment (e.g. ../../../skill/SKILL.md → ../../../SKILL.md)

No skill content changes. After this lands, 'npx skills add nutlope/hallmark' should clone + install correctly without any manual cp fallback.
2026-05-19 12:12:45 +01:00
Youssef db1072fe32 Docs · fresh hero screenshots in README, study URL example on landing page, roadmap priorities
- docs/screenshots/hero-*.jpg: 8 fresh hero-only captures of each worked example (1440×900 via Chrome headless on the local dev server). Replaces the mid-video stills in _tests/_thumbs/*-still.jpg which had video-player overlay and cropped headlines. Each is unique — no duplicates. README "Different briefs, different shapes" section now uses these and each thumbnail is a clickable link to the live deployed example.
- site/index.html: the Study verb's brief-pill swapped from "/hallmark study this landing page" to "/hallmark study together.ai · or paste a screenshot" so URL mode is visually concrete next to the lede that already names both modes. One-line change.
- ROADMAP.md: new "Now — actively working on" section at the top. N.1 covers tightening the existing 22 themes + adding 4–6 new distinct ones + lowering the bar to route to custom. N.2 covers first-class Nanobanana image generation + a new image-led theme (working title: Plate) + token discipline for generated stills.
2026-05-18 16:54:59 +01:00
Youssef 9f907ad38e Marketing · make Worked-examples cards clickable, open in new tab
Each .ex-card div is now an <a target="_blank" rel="noopener"> wrapping the same content. The hover-play video, prompt line, and .ex-card styles all work unchanged (the class already had color: inherit + focus-visible). Added one CSS line — text-decoration: none on .ex-card — so the <a> doesn't underline the card.

Linked destinations:
- examples/tally/        — SaaS, modern-minimal (from /Users/youssef/test-hallmark-9)
- examples/wayfare/      — travel booking, atmospheric (from test-hallmark-12)
- _tests/09-slow-pour/   — small-batch coffee subscription (already in site)
- examples/bananastudio/ — creative studio with playful motion (from test-hallmark-6)
- _tests/06-anya-portfolio/ — software architect personal site (already in site)
- examples/najm/         — Moroccan fashion (from test-hallmark-7)
- _tests/11-soroe-ceramics/ — small ceramics studio (already in site)
- examples/hyperlane/    — developer infrastructure (from test-hallmark-15)

site/examples/ adds ~308 KB total across the 5 copied projects. The other 3 already live under site/_tests/ so no copying needed for them.
2026-05-18 16:23:29 +01:00
Youssef f5d5c075a2 Fix · Bloom section heads left-align (hero stays centered) + drop Newsprint double-rule
- Bloom: .section__head was text-align: center with .section-label justify-content: center and .section__title margin-inline: auto — every section read as centered-everything (the AI fingerprint). Flipped to text-align: left, justify-content: flex-start, margin-inline: 0. Hero (.hero--marquee) stays centered via its own rules; the atmospheric glow does the centering work without needing every section head to repeat it. Tag stays above the title in the same column (still passes gate 66).
- Newsprint: removed border-top: 3px double var(--color-ink) from .section__head — the double rule above each section tag was reading as decorative noise on a layout that already has a strong 1 px bottom border. Single bottom border kept.
2026-05-18 15:10:02 +01:00
Youssef b41a3e60e2 Fix · Almanac sticky section heads bleeding over the top nav
Two sticky-at-top:0 elements in the same stacking context (.banner and Almanac's .section__head) overlapped during scroll because they shared --z-sticky (200) and the section head paints last in DOM order. Visible on the marketing site as the section header drawing on top of the nav as you scroll.

site/ — actual fix for the live page:
- tokens.css: split --z-sticky into --z-sticky (200, in-page) + --z-sticky-nav (300, top nav); add --banner-height: 44px so secondary stickies can offset by a single token
- components.css: .banner now uses --z-sticky-nav and reads --banner-height for its height (kept at 44 px)
- sections.css: Almanac .section__head docks at top: var(--banner-height) instead of top: 0; z-index stays at --z-sticky so the banner always out-paints when their boxes momentarily overlap

skill/ — prevent the pattern in future generated pages (without forcing sticky on every output):
- slop-test.md: new gate 68 auto-fails any second sticky-at-top:0 element when a sticky page-level nav exists; fires only when the page actually has sticky elements (S3, F2, sticky TOCs), trivial pass otherwise
- components/s3-sticky-pinned.md: recipe rewritten to use top: var(--banner-height) + --z-sticky; pairing rule explained
- components/f2-sticky-scroll-stack.md: top now calc(var(--banner-height) + var(--space-xl)) so the sticky pane docks below the nav with breathing room
- SKILL.md + preview-examples.md: gate count bumped 67 → 68

Only Almanac uses sticky section heads in the live site — no other themes affected.
2026-05-18 14:54:11 +01:00
Youssef a2cd497977 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
2026-05-18 14:45:40 +01:00
YoussefandClaude Opus 4.7 b4e454fea2 Study · emit portable design.md from diagnosis (opt-in)
After a study diagnosis, the user can now say "lock the DNA" to write
a portable design.md from the extracted DNA — same format as the
default verb's lock-the-system flow, seeded from the studied source.

URL mode populates exact tokens + fonts; image mode populates
estimated bands + candidate fonts. URL-mode emission asks the user
to attest the source is theirs or a public reference for their own
brand — third-party URLs are refused at the emission step even when
the diagnosis itself was allowed. Image mode emits without asking.

Updates skill protocol, design-md trigger list, public verb table,
README comparison, and the site's Study row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:10:35 +01:00
YoussefandClaude Opus 4.7 422065f77a Fix · install hover-stick + Atelier hero header + With/Without rename
Banner Install hover-stick:
- Smooth-scroll on a sticky banner can leave the cursor over the
  pill after click; Safari/Chrome occasionally keep :hover stuck
  even after the pointer moves away.
- Scope the hover rule to (hover: hover) and (pointer: fine) so a
  touch tap never sticks the inverted state.
- Add :focus:not(:focus-visible) reset so synthesised mouse-focus
  doesn't keep the inverted look either.
- Add a JS click handler that blur()s the pill and toggles
  pointer-events for one frame, forcing the browser to release any
  sticky :hover/:focus state.

Atelier hero header:
- Quote copy: "Restraint, repeated, becomes a signature." → "A
  workshop, not a template." Shorter, declarative, fits Atelier's
  workshop voice.
- Override the hero quote to use the upright display face
  (var(--font-display), normal style, --display-weight 900),
  matching the "Atelier" wordmark in the banner and every section
  title. Italic var(--font-serif) was making the header read as a
  pull-quote rather than the page's primary statement; Atelier's
  voice is declarative, not quoted.

With / Without rename:
- Section 06 label "Before / After" → "With / Without". Both panels
  exist now (Sonnet 4.6 alone vs Sonnet 4.6 + Hallmark) — there is
  no temporal before/after, only a presence/absence comparison.
- HTML comment updated to match.

Diptych screenshot centring:
- .ba__frame img object-position: top left → center. The full hero
  composition reads inside the 16:10 frame instead of clipping to
  the top-left corner. Other diptychs (.diptych__half, .brief-output)
  intentionally stay top-aligned — they're page screenshots where
  the masthead matters; the .ba__frame is hero-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:10:58 +01:00
YoussefandClaude Opus 4.7 ad3d07e507 Fix · mobile copy button regression — hide button, make pre tap-to-copy
The previous mobile fix (display: block + width: 100% on the button)
overflowed the frame because .code has white-space: nowrap and the
button rendered inline-flex on the same nowrap line as the command,
spilling past the right edge.

Cleaner pattern, matching what gh repo clone / npmjs / Vercel
install panes do on touch devices:

- Hide .code__copy entirely below 45rem.
- Bind a click handler on the whole [data-copy-source] pre so the
  command area itself is tap-to-copy. cursor: pointer signals it.
- Add a transient "Copied ✓" badge inside the pre on success
  (anchored top/right/centred-vertically) — replaces the button's
  label-swap on mobile. Animates in and clears after 2.2 s.
- Restore the original .code flex + align-items: center so the
  command sits vertically centred in the frame regardless of height.

JS:
- Refactor attachCopyButtons to share a copyFromSource helper.
- Source binding uses data-copy-bound; button binding uses
  data-copy-btn-bound (separate flags so re-attached cloned heroes
  don't double-bind).
- Button click stops propagation so a single tap on the visible
  button (desktop) doesn't fire both the button and source handlers.
- Both surfaces flash data-state="copied" together so CSS feedback
  works on whichever surface is visible at the active breakpoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 19:07:01 +01:00
YoussefandClaude Opus 4.7 e27a02f981 Section 06 prompt · update to dev event launch brief
The shared prompt in the Before/After Hallmark gallery used the old
Quiet Hour natural-wine brief — stale now that the before/after
thumbs were swapped to the DevForge dev-conference landing pages.
Updated the prompt to match the new content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:58:08 +01:00