diff --git a/skills/hallmark/SKILL.md b/skills/hallmark/SKILL.md
index e0715e9..77b5060 100644
--- a/skills/hallmark/SKILL.md
+++ b/skills/hallmark/SKILL.md
@@ -369,6 +369,7 @@ The non-negotiables live in [`references/`](references/). **Be precise about wha
- [`microinteractions.md`](references/microinteractions.md) — load whenever the output has *any* interactive element (buttons, inputs, modals, tabs, dropdowns, toasts, drag handles, copy buttons). That is most pages.
- [`interaction-and-states.md`](references/interaction-and-states.md) — load when the page has stateful UI (forms, command palettes, optimistic updates).
- [`responsive.md`](references/responsive.md) — load when mobile is in scope.
+- [`seo.md`](references/seo.md) — load when the build emits a full page (i.e. it owns a `
`). Carries the head block, semantic skeleton, image attributes, and structured-data rules. Skip entirely on component-scope builds.
- [`structure.md`](references/structure.md) — load only when deviating from a named macrostructure.
- [`hero-enrichment.md`](references/hero-enrichment.md) — **do NOT load at Step 4 unless the image-need check in the next paragraph returns YES.** Most builds are typography-only and never touch this file. The decision is one quick read of the brief, not a defensive auto-load.
- [`custom-craft.md`](references/custom-craft.md) — load only when an enrichment archetype requires construction (CSS art, SVG, declarative animation, etc.).
diff --git a/skills/hallmark/references/seo.md b/skills/hallmark/references/seo.md
new file mode 100644
index 0000000..9c9570d
--- /dev/null
+++ b/skills/hallmark/references/seo.md
@@ -0,0 +1,121 @@
+# Discoverability
+
+Most AI-generated pages are invisible. They ship a flawless hero and forget the ``. They stack six `
`s where a `` belonged. They size a line at 6rem and call it an `h1` because it *looks* like one. They lazy-load the hero image — the one thing that should load first. None of this shows up in a screenshot, which is exactly why it survives.
+
+Discoverability is not a marketing bolt-on. Every rule below is a decision Hallmark already makes while it builds; this file just makes it make them correctly.
+
+## Principles
+
+- **Structure carries meaning, size carries emphasis.** Heading *level* describes the document's shape. Type *scale* describes how loud a line is. They are independent. A `--text-display` line is not automatically an `h1`, and an `h2` is free to be small.
+- **One `h1`, no skipped levels.** Exactly one per page. `h2` follows `h1`; `h3` follows `h2`. Never jump a level to reach a size you liked.
+- **Landmarks before divs.** `header` · `nav` · `main` · `footer` are not optional semantics. Exactly one `main` per page, wrapping the page's actual content — not the whole body.
+- **Mark up only what is on the page.** Structured data describes visible content. If the rating isn't rendered, it isn't marked up. This is the same rule as [`anti-patterns.md` § Invented metrics](anti-patterns.md), enforced one layer deeper — invented structured data is a fabricated metric that only machines read.
+
+## The head
+
+Every emitted page carries these. No exceptions, no placeholders left as `TODO`.
+
+```html
+
+
+
+
+ Cold-brew kits for small kitchens · Ratio
+
+
+
+
+
+
+
+
+
+
+```
+
+| Field | Length | Rule |
+| --- | --- | --- |
+| `` | 50–60 chars | Page subject first, brand last, separated by ` · ` or ` — `. Unique per page. |
+| `description` | 140–160 chars | A sentence a human would read. Not a keyword list. |
+| `og:image` | 1200×630 | Real image or omit the tag. Never point at a missing file. |
+| `lang` | — | Matches the copy actually on the page, not the developer's locale. |
+
+A `` that is only the brand name is a wasted line — it's the largest text a search result will ever show for the page.
+
+## Semantic skeleton
+
+```html
+
+
+
+
+
+
+
…
+
+
…
+
+
+
+
+
+```
+
+- A `section` with no accessible name is a `div` with extra steps. Give it `aria-labelledby` pointing at its own heading, or use `div`.
+- Multiple `nav` elements need distinguishing labels (`aria-label="Primary"`, `aria-label="Footer"`).
+- Decorative wrappers stay `div`. Reaching for `section` or `article` to look tidy is noise.
+
+## Images
+
+- **`alt` describes function, not appearance.** What would you say to someone who can't see it and needs to keep reading? *"Brewer disassembled into six parts"* — not *"image of a coffee product on a white background"*.
+- **Decorative images take `alt=""`.** Empty, not missing. Missing `alt` makes a screen reader read the filename.
+- **Always set `width` and `height`.** They reserve the box and stop the page from jumping as images arrive. CSS still controls the rendered size.
+- **The hero image loads eagerly.** It is almost always the largest element on screen; lazy-loading it delays the one paint the visitor is waiting for.
+
+```html
+
+
+
+
+
+```
+
+## Structured data
+
+Emit one JSON-LD block in the head, only for what the page genuinely is, and only describing content a visitor can see. One `@type` per page is normal; two is the ceiling.
+
+| Page | `@type` |
+| --- | --- |
+| Company / product site | `Organization`, or `LocalBusiness` when there's a real address |
+| Single product | `Product` |
+| Written piece | `Article` (`author` and `datePublished` required) |
+| Q&A block already on the page | `FAQPage` |
+| Any page below the root | `BreadcrumbList` |
+
+```html
+
+```
+
+Ratings are the trap. `aggregateRating` is only legal when the reviews it summarises are rendered on that page, with real counts. If the brief didn't supply reviews, the page has no rating — the same way it has no *"+47 % conversion"*. Marking up a rating that nobody wrote is not an optimisation; it's a manual action waiting to happen.
+
+## Bans
+
+- **No missing `` or `description`.** Shipping either as `TODO`, `Untitled`, or the brand name alone.
+- **More than one `h1`**, or a heading level skipped to reach a size.
+- **Headings chosen by size.** `h3` for a small caption is a structural lie; use a `p` with a label class.
+- **`div` where a landmark belonged.** No `main`, or several.
+- **`alt="image of…"`, `alt="photo"`, or keyword-stuffed alt.** Also: missing `alt` on a decorative image — use `alt=""`.
+- **Lazy-loading the hero image.** Delays the largest paint on purpose.
+- **`` without `width`/`height`.** Guarantees layout shift.
+- **Structured data for content that isn't on the page** — reviews, ratings, FAQs, breadcrumbs to routes that don't exist. Machine-readable fabrication is still fabrication.
+- **Keyword-stuffed copy.** Copy is written for the reader. See [`copy.md`](copy.md).
+- **`og:image` pointing at a file that was never generated.**