mirror of
https://github.com/Nutlope/hallmark.git
synced 2026-08-14 12:35:33 +02:00
Move theme picker out of navbar to a fixed bottom-left chip
The 12-theme popover was congested when opened inline in the navbar. Now it lives as a floating chip in the bottom-left corner: always reachable on desktop and mobile, popover opens upward, and the navbar is a clean two-column wordmark + meta layout. - index.html: themer markup moved to end of <body>, navbar simplified - components.css: .themer is position: fixed with bottom/left anchors, popover opens upward (bottom: 100% + 0.5rem), responsive grid collapses to 2 columns under 60rem - sections.css: removed .nav__themer rules; .nav restored to flex space-between - README.md: rewritten concise + complete, mirrors the v0.2.0 surface (10 reference files, 12 themes, 4 verbs, 20-question slop test)
This commit is contained in:
@@ -8,15 +8,54 @@ A design skill for AI coding assistants. Makes the UIs they generate look made,
|
||||
|
||||
## What it is
|
||||
|
||||
Hallmark is a single, opinionated skill — short on purpose — that teaches Claude Code / Cursor / Codex a firm, consensus-backed set of rules for typography, colour, layout, motion, interaction, responsive behaviour, and copy. It refuses to design without a confirmed audience, use case, and tone. It refuses to emit the on-distribution defaults every LLM was trained into (Inter + purple gradient + centred hero + 3-column icon tiles).
|
||||
A single, opinionated skill — short on purpose — that teaches Claude Code, Cursor, or Codex a firm, consensus-backed set of rules for typography, colour, layout, motion, interaction, microinteractions, copy, responsive behaviour, and structural variety. It refuses to design without a confirmed audience, use case, and tone, and refuses to emit the on-distribution defaults every LLM was trained into.
|
||||
|
||||
It ships one holistic verb and two auxiliary ones:
|
||||
The differentiator: Hallmark insists on **structural variety**, not just visual variety. Two pages by Hallmark for two different briefs should not share the same hero → 3-feature → CTA → footer rhythm.
|
||||
|
||||
| Invocation | What it does |
|
||||
---
|
||||
|
||||
## Four verbs
|
||||
|
||||
| Verb | What it does |
|
||||
| --- | --- |
|
||||
| *(default)* | Build / edit UI. Requires design context before touching code. |
|
||||
| `hallmark audit <target>` | Score existing code against the named anti-patterns. Returns a punch list. |
|
||||
| `hallmark refine <target>` | Apply the ruleset to polish existing code with the smallest possible diff. |
|
||||
| *(default)* | Build new UI — passes the design-context gate, picks a structural fingerprint, applies the ruleset, runs the slop test before handing back. |
|
||||
| `hallmark audit <target>` | Score existing code against the named anti-patterns + structural sameness. Returns a punch list. No edits. |
|
||||
| `hallmark refine <target>` | Polish in place. Smallest possible diff. Preserves structure. |
|
||||
| `hallmark redesign <target> [--mood <name>]` | Throw out the structure, keep copy + IA + brand, rebuild with a deliberately different structural fingerprint. |
|
||||
|
||||
---
|
||||
|
||||
## What's inside
|
||||
|
||||
**Skill** — [`skill/SKILL.md`](skill/SKILL.md) plus ten reference files:
|
||||
|
||||
- [`typography.md`](skill/references/typography.md) — banned defaults, pairing rules, weight extremes, scale ratios
|
||||
- [`color.md`](skill/references/color.md) — OKLCH palette construction, accent discipline (≤3% area), dark-mode recipe
|
||||
- [`layout-and-space.md`](skill/references/layout-and-space.md) — 4pt scale, asymmetry, grid-breaks, depth via weight not shadow
|
||||
- [`structure.md`](skill/references/structure.md) — six axes of structural variety (heading placement, body composition, divider, button voice, image, reveal); the per-theme structural fingerprint table
|
||||
- [`motion.md`](skill/references/motion.md) — duration buckets, three named easings, no bounce on UI, reduced-motion default
|
||||
- [`microinteractions.md`](skill/references/microinteractions.md) — 14 interaction recipes (button press, focus, modal, toast, optimistic update, command palette, drag, copy-to-clipboard, search-as-you-type) and the 20 named microinteraction tells
|
||||
- [`interaction-and-states.md`](skill/references/interaction-and-states.md) — eight states per element, focus-visible spec, 44px hit targets, undo over confirm
|
||||
- [`responsive.md`](skill/references/responsive.md) — mobile-first, content-driven breakpoints, `dvh` not `vh`, safe-area-insets
|
||||
- [`copy.md`](skill/references/copy.md) — specific verbs, three-part errors, standalone link text, proper typographic punctuation
|
||||
- [`anti-patterns.md`](skill/references/anti-patterns.md) — 30+ named tells with severity, why they fail, and the fix
|
||||
|
||||
**Slop test (20 questions)** — every output must answer *no* to all twenty before shipping. Visual (8), structural (2), microinteraction (10).
|
||||
|
||||
**Site** — [`site/`](site/) is a self-demonstrating landing page. Hand-written HTML + CSS + ES module, no framework, no build step. Uses Together AI's "The Future" typeface plus Google Fonts.
|
||||
|
||||
**Twelve themes**, four categories, each with its own structural fingerprint:
|
||||
|
||||
- **Editorial** — Specimen, Newsprint, Atelier
|
||||
- **Soft** — Garden, Salon, Linen
|
||||
- **Technical** — Midnight, Terminal, Almanac
|
||||
- **Bold** — Brutal, Manifesto, Sport
|
||||
|
||||
Each theme overrides not only colour and typography but section-heading placement, column counts, divider style, button voice, and reveal pattern. The same landing page reorganises itself per theme, demonstrating the structural-variety principle.
|
||||
|
||||
**Two test specimens** — [`site/_example-bakery/`](site/_example-bakery/) (an editorial bakery announcement, output of a real `hallmark` run) and [`site/_example-cmdk/`](site/_example-cmdk/) (a keyboard-first command palette demonstrating the microinteraction canon).
|
||||
|
||||
**Roadmap** — [`ROADMAP.md`](ROADMAP.md) lists Tier 1, 2, and 3 work, plus an explicit "things to *not* do" list and measurement criteria.
|
||||
|
||||
---
|
||||
|
||||
@@ -28,7 +67,7 @@ It ships one holistic verb and two auxiliary ones:
|
||||
npx skills add hallmark
|
||||
```
|
||||
|
||||
### Claude Code
|
||||
### Claude Code (manual)
|
||||
|
||||
Copy [`skill/SKILL.md`](skill/SKILL.md) and [`skill/references/`](skill/references/) into `~/.claude/skills/hallmark/`.
|
||||
|
||||
@@ -36,70 +75,33 @@ Copy [`skill/SKILL.md`](skill/SKILL.md) and [`skill/references/`](skill/referenc
|
||||
|
||||
Create `.cursor/rules/hallmark.mdc` with the body of `SKILL.md` (no frontmatter).
|
||||
|
||||
### Manual
|
||||
|
||||
`git clone` this repo; copy `skill/` into whatever config directory your agent uses.
|
||||
|
||||
---
|
||||
|
||||
## Philosophy
|
||||
|
||||
Five skills — [impeccable](https://github.com/pbakaus/impeccable), [kami](https://github.com/tw93/kami), [taste-skill](https://github.com/Leonxlnx/taste-skill), Anthropic's [frontend-design skill](https://github.com/anthropics/skills), and the Claude [frontend aesthetics cookbook](https://platform.claude.com/cookbook/coding-prompting-for-frontend-aesthetics) — have converged on roughly the same anti-slop ruleset. Hallmark takes that consensus, restates it in one voice, and keeps the surface small so it actually gets loaded into context.
|
||||
|
||||
Hallmark's distinct choices:
|
||||
|
||||
- **One skill, three verbs.** Not eighteen commands. Use the default; reach for `audit` or `refine` when you need them.
|
||||
- **Design-context gate.** No audience + use case + tone → no design. The skill will ask.
|
||||
- **Tone as a first-class decision.** "Clean and modern" is rejected. You pick an extreme: editorial, brutalist, soft, utilitarian, luxury, playful, technical, austere.
|
||||
- **The slop test.** Before handing back, the skill runs ten yes/no checks. One yes fails the output.
|
||||
|
||||
---
|
||||
|
||||
## The landing page
|
||||
|
||||
[`site/`](site/) is a live specimen — it's the skill applied to itself. Serve it statically:
|
||||
### View the landing page locally
|
||||
|
||||
```
|
||||
cd site && python3 -m http.server 4173
|
||||
# → http://localhost:4173
|
||||
```
|
||||
|
||||
The page uses Together AI's "The Future" typeface (distributed here with permission for demonstration), an OKLCH warm-oat palette anchored at hue 80, a single signal-orange accent (`#FC4C02`, ≤ 3 % of any view), and a drafting-specimen layout language — hairline rules, small-caps section numbering, asymmetric columns.
|
||||
|
||||
No framework. No build step. One `index.html`, four stylesheets, one ES module.
|
||||
|
||||
---
|
||||
|
||||
## Repo layout
|
||||
## Philosophy
|
||||
|
||||
```
|
||||
hallmark/
|
||||
├── README.md ← you are here
|
||||
├── LICENSE ← MIT
|
||||
├── package.json ← for `npx skills add`
|
||||
├── skill/
|
||||
│ ├── SKILL.md ← main routing + principles
|
||||
│ └── references/
|
||||
│ ├── typography.md
|
||||
│ ├── color.md
|
||||
│ ├── layout-and-space.md
|
||||
│ ├── motion.md
|
||||
│ ├── interaction-and-states.md
|
||||
│ ├── responsive.md
|
||||
│ ├── copy.md
|
||||
│ └── anti-patterns.md
|
||||
└── site/
|
||||
├── index.html
|
||||
├── css/{tokens,base,components,sections}.css
|
||||
├── js/main.js
|
||||
└── fonts/the-future-*.woff2
|
||||
```
|
||||
Five skills — [impeccable](https://github.com/pbakaus/impeccable), [kami](https://github.com/tw93/kami), [taste-skill](https://github.com/Leonxlnx/taste-skill), Anthropic's [frontend-design skill](https://github.com/anthropics/skills), and the Claude [frontend aesthetics cookbook](https://platform.claude.com/cookbook/coding-prompting-for-frontend-aesthetics) — have converged on roughly the same anti-slop ruleset. Hallmark takes that consensus, restates it in one voice, fills the gap on motion and microinteractions, and adds *structural* variety as a first-class principle.
|
||||
|
||||
Distinct choices:
|
||||
|
||||
- **One skill, four verbs.** Not eighteen commands. Use the default; reach for `audit`, `refine`, or `redesign` when you need them.
|
||||
- **Design-context gate.** No audience + use case + tone → no design. The skill asks.
|
||||
- **Tone as a first-class decision.** "Clean and modern" is rejected. Pick an extreme: editorial, brutalist, soft, utilitarian, luxury, playful, technical, austere.
|
||||
- **Structural fingerprint.** Every page picks one option from each of six axes. Two consecutive outputs in a session should never share the same fingerprint.
|
||||
- **Microinteractions are not decoration.** Silent success over celebratory toasts. Optimistic update + Undo over confirm dialogs. Hover delay 800 ms, focus delay 0 ms.
|
||||
- **The slop test.** Twenty yes/no checks before handing back. One yes fails the output.
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
|
||||
Built on the open work of Paul Bakaus ([impeccable](https://github.com/pbakaus/impeccable)), tw93 ([kami](https://github.com/tw93/kami)), Leonxlnx ([taste-skill](https://github.com/Leonxlnx/taste-skill)), and Anthropic's skills team. Where their rules overlapped, Hallmark adopted them; where they diverged, Hallmark picked. See each source for its own deeper treatment of the same problem.
|
||||
Built on the open work of Paul Bakaus ([impeccable](https://github.com/pbakaus/impeccable)), tw93 ([kami](https://github.com/tw93/kami)), Leonxlnx ([taste-skill](https://github.com/Leonxlnx/taste-skill)), Anthropic's skills team ([frontend-design](https://github.com/anthropics/skills) and [canvas-design](https://github.com/anthropics/skills)), [DESIGN.md](https://getdesign.md) (Google Stitch), MC Dean's [63 design skills](https://marieclairedean.substack.com/p/i-built-63-design-skills-for-claude), [PencilPlaybook](https://github.com/stevembarclay/pencilplaybook), and the [Slopless](https://slopless.design) tactile-rebellion canon. Where rules overlapped, Hallmark adopted; where they diverged, Hallmark picked.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+72
-30
@@ -23,12 +23,15 @@
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
/* — Theme picker (button + popover) ————————————————————————— */
|
||||
/* — Theme picker (fixed bottom-left chip + upward popover) ————— */
|
||||
.themer {
|
||||
position: relative;
|
||||
position: fixed;
|
||||
left: max(1rem, env(safe-area-inset-left));
|
||||
bottom: max(1rem, env(safe-area-inset-bottom));
|
||||
z-index: var(--z-sticky);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-xs);
|
||||
gap: 0.5rem;
|
||||
font-family: var(--font-label);
|
||||
font-size: 0.6875rem;
|
||||
letter-spacing: var(--tracking-label);
|
||||
@@ -39,15 +42,25 @@
|
||||
.themer__trigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.55rem 0.9rem;
|
||||
background: var(--color-paper-2);
|
||||
gap: 0.55rem;
|
||||
padding: 0.55rem 0.85rem 0.55rem 0.6rem;
|
||||
background: var(--color-paper);
|
||||
border: var(--rule-hair) solid var(--color-rule-2);
|
||||
color: var(--color-ink);
|
||||
font: inherit;
|
||||
letter-spacing: 0.14em;
|
||||
cursor: pointer;
|
||||
min-height: 36px;
|
||||
/* explicit transitions, not transition-all */
|
||||
transition: background-color var(--dur-micro) var(--ease-out),
|
||||
border-color var(--dur-micro) var(--ease-out),
|
||||
color var(--dur-micro) var(--ease-out);
|
||||
box-shadow: 0 1px 2px oklch(20% 0.02 60 / 0.05),
|
||||
0 8px 24px -8px oklch(20% 0.02 60 / 0.10);
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.themer__trigger:hover { border-color: var(--color-ink); }
|
||||
}
|
||||
|
||||
.themer__trigger:focus-visible {
|
||||
@@ -55,6 +68,16 @@
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Tiny accent swatch on the trigger — confirms current theme at a glance */
|
||||
.themer__trigger-swatch {
|
||||
width: 0.55rem;
|
||||
height: 0.55rem;
|
||||
background: var(--color-accent);
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.themer__trigger-label {
|
||||
color: var(--color-muted);
|
||||
}
|
||||
@@ -65,39 +88,45 @@
|
||||
}
|
||||
|
||||
.themer__trigger-caret {
|
||||
width: 0.45em;
|
||||
height: 0.45em;
|
||||
width: 0.4em;
|
||||
height: 0.4em;
|
||||
border-right: 1.5px solid currentColor;
|
||||
border-bottom: 1.5px solid currentColor;
|
||||
transform: rotate(45deg) translateY(-1px);
|
||||
transform: rotate(-135deg) translate(-1px, 1px); /* points up — popover opens up */
|
||||
transition: transform var(--dur-short) var(--ease-out);
|
||||
}
|
||||
|
||||
.themer[aria-expanded="true"] .themer__trigger-caret {
|
||||
transform: rotate(225deg) translateY(2px);
|
||||
transform: rotate(45deg) translate(-2px, -1px); /* points down when open */
|
||||
}
|
||||
|
||||
/* Keyboard-shortcut hint — delay-reveals on hover (Linear / Notion pattern) */
|
||||
/* Keyboard-shortcut hint — delay-reveals on hover, instant on focus */
|
||||
.themer__kbd {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3em;
|
||||
margin-left: 0.5rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
justify-content: center;
|
||||
padding: 0.15rem 0.45rem;
|
||||
font-family: var(--font-label);
|
||||
font-size: 0.625rem;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--color-muted);
|
||||
background: var(--color-paper-3);
|
||||
background: var(--color-paper-2);
|
||||
border: var(--rule-hair) solid var(--color-rule);
|
||||
opacity: 0;
|
||||
transform: translateX(-4px);
|
||||
pointer-events: none;
|
||||
/* hover delay: 1.2s before reveal — Notion/Linear pattern */
|
||||
min-height: 28px;
|
||||
/* hover delay: 1.2s before reveal */
|
||||
transition: opacity 180ms var(--ease-out) 1.2s,
|
||||
transform 180ms var(--ease-out) 1.2s;
|
||||
}
|
||||
|
||||
.themer__kbd::before {
|
||||
content: "press ";
|
||||
margin-right: 0.35em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.themer__trigger:hover ~ .themer__kbd {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
@@ -107,7 +136,7 @@
|
||||
.themer[aria-expanded="true"] .themer__kbd {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
/* no delay on focus or open — keyboard users want it now */
|
||||
/* no delay on focus or open */
|
||||
transition: opacity 180ms var(--ease-out),
|
||||
transform 180ms var(--ease-out);
|
||||
}
|
||||
@@ -117,30 +146,34 @@
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
@media (max-width: 56rem) {
|
||||
@media (max-width: 40rem) {
|
||||
.themer__kbd { display: none; }
|
||||
.themer__trigger { padding-block: 0.6rem; }
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.themer__kbd { transition-duration: 0.01ms; transition-delay: 0.01ms; }
|
||||
}
|
||||
|
||||
/* Popover panel */
|
||||
/* Popover panel — opens upward from the chip */
|
||||
.themer__panel {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(-4px);
|
||||
width: min(48rem, calc(100vw - 2rem));
|
||||
bottom: calc(100% + 0.5rem);
|
||||
left: 0;
|
||||
transform: translateY(4px);
|
||||
width: min(40rem, calc(100vw - 2rem));
|
||||
max-height: calc(100dvh - 6rem);
|
||||
overflow-y: auto;
|
||||
background: var(--color-paper);
|
||||
border: var(--rule-hair) solid var(--color-rule-2);
|
||||
padding: var(--space-lg);
|
||||
z-index: var(--z-dropdown);
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: var(--space-lg);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 24px 60px -20px oklch(20% 0.02 60 / 0.18),
|
||||
0 0 0 1px oklch(20% 0.02 60 / 0.04);
|
||||
transition: opacity var(--dur-short) var(--ease-out),
|
||||
transform var(--dur-short) var(--ease-out);
|
||||
}
|
||||
@@ -148,18 +181,27 @@
|
||||
.themer[aria-expanded="true"] .themer__panel {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
@media (max-width: 60rem) {
|
||||
.themer__panel {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
width: min(28rem, calc(100vw - 2rem));
|
||||
left: auto;
|
||||
right: 0;
|
||||
transform: translateY(-4px);
|
||||
width: min(26rem, calc(100vw - 2rem));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 36rem) {
|
||||
.themer__panel {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
/* anchor to viewport edges so it doesn't clip on small screens */
|
||||
left: 0;
|
||||
right: auto;
|
||||
width: calc(100vw - 2rem);
|
||||
max-width: 26rem;
|
||||
padding: var(--space-md);
|
||||
gap: var(--space-md);
|
||||
}
|
||||
.themer[aria-expanded="true"] .themer__panel { transform: translateY(0); }
|
||||
}
|
||||
|
||||
.themer__group {
|
||||
|
||||
+2
-14
@@ -11,35 +11,23 @@
|
||||
|
||||
/* — Nav ————————————————————————————————————————————— */
|
||||
.nav {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-lg);
|
||||
padding-block: var(--space-md);
|
||||
}
|
||||
|
||||
.nav__themer { justify-self: center; }
|
||||
|
||||
.nav__meta {
|
||||
font-family: var(--font-label);
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-muted);
|
||||
letter-spacing: var(--tracking-label);
|
||||
text-transform: uppercase;
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.nav__meta a { color: var(--color-ink); }
|
||||
|
||||
@media (max-width: 56rem) {
|
||||
.nav {
|
||||
grid-template-columns: auto auto;
|
||||
grid-template-rows: auto auto;
|
||||
row-gap: var(--space-md);
|
||||
}
|
||||
.nav__themer { grid-column: 1 / -1; justify-self: stretch; }
|
||||
}
|
||||
|
||||
/* — Section container ——————————————————————————————— */
|
||||
.section {
|
||||
display: grid;
|
||||
|
||||
+132
-131
@@ -35,135 +35,6 @@
|
||||
<!-- NAV -->
|
||||
<nav class="nav" aria-label="Primary">
|
||||
<a href="#top" class="wordmark">Hallmark</a>
|
||||
|
||||
<div class="themer nav__themer" aria-expanded="false">
|
||||
<button class="themer__trigger" type="button" id="themer-trigger" aria-haspopup="dialog" aria-expanded="false">
|
||||
<span class="themer__trigger-label">Theme · </span>
|
||||
<span class="themer__trigger-current" data-theme-current>Specimen</span>
|
||||
<span class="themer__trigger-caret" aria-hidden="true"></span>
|
||||
</button>
|
||||
|
||||
<span class="themer__kbd" aria-hidden="true">
|
||||
press <span class="themer__kbd-key">T</span>
|
||||
</span>
|
||||
|
||||
<div class="themer__panel" id="themer-panel" role="dialog" aria-label="Choose a theme">
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Editorial</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="specimen" aria-pressed="true">
|
||||
<span>Specimen</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.012 80)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(18% 0.010 60)"></span>
|
||||
<span class="themer__swatch" style="background: #FC4C02"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="newsprint" aria-pressed="false">
|
||||
<span>Newsprint</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(95% 0.020 60)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(18% 0.012 250)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(48% 0.13 30)"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="atelier" aria-pressed="false">
|
||||
<span>Atelier</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.012 70)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(12% 0.012 40)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(58% 0.115 65)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Soft</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="garden" aria-pressed="false">
|
||||
<span>Garden</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.020 115)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(24% 0.050 160)"></span>
|
||||
<span class="themer__swatch" style="background: #B6485E"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="salon" aria-pressed="false">
|
||||
<span>Salon</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(95% 0.014 65)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(22% 0.024 35)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(58% 0.105 130)"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="linen" aria-pressed="false">
|
||||
<span>Linen</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(94% 0.018 95)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(24% 0.022 140)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(54% 0.080 140)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Technical</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="midnight" aria-pressed="false">
|
||||
<span>Midnight</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(14% 0.010 40)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(94% 0.006 80)"></span>
|
||||
<span class="themer__swatch" style="background: #FC4C02"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="terminal" aria-pressed="false">
|
||||
<span>Terminal</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(11% 0.010 145)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(86% 0.150 138)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(78% 0.180 138)"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="almanac" aria-pressed="false">
|
||||
<span>Almanac</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(94% 0.012 80)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(16% 0.012 45)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(38% 0.135 250)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Bold</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="brutal" aria-pressed="false">
|
||||
<span>Brutal</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(98% 0.003 90)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(10% 0.005 60)"></span>
|
||||
<span class="themer__swatch" style="background: #FF2E2E"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="manifesto" aria-pressed="false">
|
||||
<span>Manifesto</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(98% 0.004 90)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(8% 0.005 60)"></span>
|
||||
<span class="themer__swatch" style="background: #E51A1A"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="sport" aria-pressed="false">
|
||||
<span>Sport</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.006 250)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(16% 0.080 260)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(58% 0.190 35)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="nav__meta">
|
||||
v0.1 · <a href="#install" class="link">Install</a>
|
||||
</div>
|
||||
@@ -454,8 +325,8 @@
|
||||
<article class="step">
|
||||
<span class="step__num">III</span>
|
||||
<div>
|
||||
<h3 class="step__head">Ship, audit, refine</h3>
|
||||
<p class="step__sub">The default verb builds. <code>hallmark audit</code> scores existing code against the tells. <code>hallmark refine</code> polishes in place.</p>
|
||||
<h3 class="step__head">Ship, audit, refine, redesign</h3>
|
||||
<p class="step__sub">The default verb builds. <code>hallmark audit</code> scores existing code against the tells. <code>hallmark refine</code> polishes in place. <code>hallmark redesign</code> rethinks the structure.</p>
|
||||
</div>
|
||||
<div class="step__body">
|
||||
<pre class="code code--block">$ claude "hallmark audit ./components/hero.tsx"
|
||||
@@ -526,6 +397,136 @@
|
||||
|
||||
</main>
|
||||
|
||||
<!-- Theme picker — fixed bottom-left, never in the navbar. -->
|
||||
<div class="themer" aria-expanded="false">
|
||||
<button class="themer__trigger" type="button" id="themer-trigger" aria-haspopup="dialog" aria-expanded="false">
|
||||
<span class="themer__trigger-swatch" aria-hidden="true"></span>
|
||||
<span class="themer__trigger-label">Theme · </span>
|
||||
<span class="themer__trigger-current" data-theme-current>Specimen</span>
|
||||
<span class="themer__trigger-caret" aria-hidden="true"></span>
|
||||
</button>
|
||||
|
||||
<span class="themer__kbd" aria-hidden="true">
|
||||
<span class="themer__kbd-key">T</span>
|
||||
</span>
|
||||
|
||||
<div class="themer__panel" id="themer-panel" role="dialog" aria-label="Choose a theme">
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Editorial</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="specimen" aria-pressed="true">
|
||||
<span>Specimen</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.012 80)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(18% 0.010 60)"></span>
|
||||
<span class="themer__swatch" style="background: #FC4C02"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="newsprint" aria-pressed="false">
|
||||
<span>Newsprint</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(95% 0.020 60)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(18% 0.012 250)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(48% 0.13 30)"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="atelier" aria-pressed="false">
|
||||
<span>Atelier</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.012 70)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(12% 0.012 40)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(58% 0.115 65)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Soft</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="garden" aria-pressed="false">
|
||||
<span>Garden</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.020 115)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(24% 0.050 160)"></span>
|
||||
<span class="themer__swatch" style="background: #B6485E"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="salon" aria-pressed="false">
|
||||
<span>Salon</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(95% 0.014 65)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(22% 0.024 35)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(58% 0.105 130)"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="linen" aria-pressed="false">
|
||||
<span>Linen</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(94% 0.018 95)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(24% 0.022 140)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(54% 0.080 140)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Technical</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="midnight" aria-pressed="false">
|
||||
<span>Midnight</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(14% 0.010 40)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(94% 0.006 80)"></span>
|
||||
<span class="themer__swatch" style="background: #FC4C02"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="terminal" aria-pressed="false">
|
||||
<span>Terminal</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(11% 0.010 145)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(86% 0.150 138)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(78% 0.180 138)"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="almanac" aria-pressed="false">
|
||||
<span>Almanac</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(94% 0.012 80)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(16% 0.012 45)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(38% 0.135 250)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="themer__group">
|
||||
<p class="themer__group-label">Bold</p>
|
||||
<button class="themer__btn" type="button" data-theme-btn="brutal" aria-pressed="false">
|
||||
<span>Brutal</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(98% 0.003 90)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(10% 0.005 60)"></span>
|
||||
<span class="themer__swatch" style="background: #FF2E2E"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="manifesto" aria-pressed="false">
|
||||
<span>Manifesto</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(98% 0.004 90)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(8% 0.005 60)"></span>
|
||||
<span class="themer__swatch" style="background: #E51A1A"></span>
|
||||
</span>
|
||||
</button>
|
||||
<button class="themer__btn" type="button" data-theme-btn="sport" aria-pressed="false">
|
||||
<span>Sport</span>
|
||||
<span class="themer__swatches" aria-hidden="true">
|
||||
<span class="themer__swatch" style="background: oklch(96% 0.006 250)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(16% 0.080 260)"></span>
|
||||
<span class="themer__swatch" style="background: oklch(58% 0.190 35)"></span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user