← back to Homesonspec
Design system iter-1: Claude Design bundle (tokens + buttons/badges/home-card/map-legend cards w/ @dsCard markers) staged for DesignSync push
8b8126df29eb90089d177a81a46ea1393e5361d5 · 2026-07-22 17:29:21 -0700 · Steve
Files touched
A design-system/README.mdA design-system/components/badges/index.htmlA design-system/components/buttons/index.htmlA design-system/components/home-card/index.htmlA design-system/components/map-legend/index.htmlA design-system/tokens.html
Diff
commit 8b8126df29eb90089d177a81a46ea1393e5361d5
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 22 17:29:21 2026 -0700
Design system iter-1: Claude Design bundle (tokens + buttons/badges/home-card/map-legend cards w/ @dsCard markers) staged for DesignSync push
---
design-system/README.md | 31 +++++++++++
design-system/components/badges/index.html | 30 +++++++++++
design-system/components/buttons/index.html | 40 ++++++++++++++
design-system/components/home-card/index.html | 43 +++++++++++++++
design-system/components/map-legend/index.html | 33 ++++++++++++
design-system/tokens.html | 75 ++++++++++++++++++++++++++
6 files changed, 252 insertions(+)
diff --git a/design-system/README.md b/design-system/README.md
new file mode 100644
index 0000000..861e9e4
--- /dev/null
+++ b/design-system/README.md
@@ -0,0 +1,31 @@
+# HomesOnSpec — Claude Design system bundle
+
+This directory is the **source bundle** for the HomesOnSpec design system on
+`claude.ai/design`. It is pushed via the **DesignSync** tool (list → finalize_plan →
+write_files), one component at a time.
+
+## Contract
+- Tokens here mirror `apps/web/src/app/globals.css` `@theme` **1:1**. The live app and
+ the synced library must never drift — change a token in both, or in neither.
+- Every preview's **first line** is `<!-- @dsCard group="…" -->`. The Design System pane
+ builds its card index from that marker (no explicit `register_assets` needed).
+
+## Cards
+| Path | Group | Renders |
+|---|---|---|
+| `tokens.html` | Foundations | brand + accent + status ramps, type scale |
+| `components/buttons/index.html` | Components | primary / accent / ghost, two sizes |
+| `components/badges/index.html` | Components | verified label + status badges |
+| `components/home-card/index.html` | Components | listing card (price, beds, verified, builder) |
+| `components/map-legend/index.html` | Components | map legend + field on/off toggle |
+
+## Push (blocked on `/login`)
+DesignSync needs a `claude.ai` login with design scopes. In this session:
+1. `/login` (adds design-system scopes to the token).
+2. `DesignSync list_projects` → pick/create the **HomesOnSpec** project (type must be
+ `PROJECT_TYPE_DESIGN_SYSTEM`).
+3. `finalize_plan` with writes `tokens.html`, `components/**/index.html`, `localDir` = this dir.
+4. `write_files` (localPath uploads — contents never enter model context).
+
+Until then the bundle is committed to git and the live app already renders from the same
+tokens, so nothing is blocked except the external mirror.
diff --git a/design-system/components/badges/index.html b/design-system/components/badges/index.html
new file mode 100644
index 0000000..6592be8
--- /dev/null
+++ b/design-system/components/badges/index.html
@@ -0,0 +1,30 @@
+<!-- @dsCard group="Components" -->
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Badges</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
+body{font-family:'Inter',system-ui,sans-serif;margin:0;background:#f7faf9;padding:32px;color:#0f2b2a}
+.eyebrow{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.18em;color:#226b69;margin-bottom:14px}
+.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:14px}
+.badge{display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:3px 11px;font:500 12px/1.4 'Inter',sans-serif}
+.verified{background:#f0f9f8;color:#1e5654;box-shadow:inset 0 0 0 1px #b4deda}
+.ready{background:#fef0d0;color:#8d4114}
+.neutral{background:#f2f4f4;color:#5b6b6a}
+.dot{width:8px;height:8px;border-radius:50%}
+</style>
+</head>
+<body>
+ <p class="eyebrow">Badges & verification labels</p>
+ <div class="row">
+ <span class="badge verified">✓ Verified from source</span>
+ <span class="badge ready"><i class="dot" style="background:#16a34a"></i>Move-in ready</span>
+ <span class="badge neutral"><i class="dot" style="background:#f59e0b"></i>Under construction</span>
+ <span class="badge neutral">🕓 Verified May 20, 3:17 AM</span>
+ </div>
+ <p style="font-size:13px;color:#5b6b6a">Verified badge = the field carries per-source evidence. Status badges reuse the construction-status token colors so the map legend and the cards agree.</p>
+</body>
+</html>
diff --git a/design-system/components/buttons/index.html b/design-system/components/buttons/index.html
new file mode 100644
index 0000000..7e057d9
--- /dev/null
+++ b/design-system/components/buttons/index.html
@@ -0,0 +1,40 @@
+<!-- @dsCard group="Components" -->
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Buttons</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
+:root{--brand-50:#f0f9f8;--brand-200:#b4deda;--brand-700:#1e5654;--brand-800:#1b4645;--brand-950:#081e1e;
+ --accent-400:#f4a934;--accent-500:#ed8f16;}
+body{font-family:'Inter',system-ui,sans-serif;margin:0;background:#f7faf9;padding:32px;color:#0f2b2a}
+.eyebrow{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.18em;color:#226b69;margin-bottom:14px}
+.row{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-bottom:16px}
+.btn{display:inline-flex;align-items:center;gap:8px;border:0;border-radius:999px;padding:10px 20px;
+ font:600 14px/1 'Inter',sans-serif;cursor:pointer;transition:.15s}
+.primary{background:var(--brand-700);color:#fff;box-shadow:0 1px 2px rgba(16,50,49,.12)}
+.primary:hover{background:var(--brand-800)}
+.accent{background:var(--accent-500);color:var(--brand-950)}
+.accent:hover{background:var(--accent-400)}
+.ghost{background:#fff;color:var(--brand-800);box-shadow:inset 0 0 0 1px var(--brand-200)}
+.ghost:hover{background:var(--brand-50)}
+.small{padding:7px 14px;font-size:13px}
+</style>
+</head>
+<body>
+ <p class="eyebrow">Buttons</p>
+ <div class="row">
+ <button class="btn primary">Search</button>
+ <button class="btn accent">Contact a builder</button>
+ <button class="btn ghost">Save home</button>
+ </div>
+ <div class="row">
+ <button class="btn primary small">Primary · sm</button>
+ <button class="btn accent small">Accent · sm</button>
+ <button class="btn ghost small">Ghost · sm</button>
+ </div>
+ <p style="font-size:13px;color:#5b6b6a">Pill radius, brand teal primary / honey accent for the single highest-intent CTA per view.</p>
+</body>
+</html>
diff --git a/design-system/components/home-card/index.html b/design-system/components/home-card/index.html
new file mode 100644
index 0000000..d58bf5e
--- /dev/null
+++ b/design-system/components/home-card/index.html
@@ -0,0 +1,43 @@
+<!-- @dsCard group="Components" -->
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Home card</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600&family=Inter:wght@400;500;600&display=swap');
+body{font-family:'Inter',system-ui,sans-serif;margin:0;background:#f7faf9;padding:32px;color:#0f2b2a}
+.eyebrow{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.18em;color:#226b69;margin-bottom:14px}
+.card{width:320px;border-radius:20px;background:#fff;border:1px solid rgba(180,222,218,.5);overflow:hidden;
+ box-shadow:0 1px 2px rgba(16,50,49,.05),0 8px 24px -14px rgba(16,50,49,.2)}
+.photo{height:170px;background:linear-gradient(135deg,#1e5654,#2f8783);position:relative}
+.photo .status{position:absolute;top:12px;left:12px;display:inline-flex;align-items:center;gap:5px;
+ background:#fff;border-radius:999px;padding:3px 10px;font:500 12px/1.4 'Inter';color:#8d4114}
+.photo .status .dot{width:8px;height:8px;border-radius:50%;background:#16a34a}
+.body{padding:14px 16px 16px}
+.price{font-family:'Fraunces',serif;font-weight:600;font-size:24px;letter-spacing:-.01em}
+.addr{font-size:14px;color:#123231;margin-top:2px}
+.meta{display:flex;gap:14px;font-size:13px;color:#5b6b6a;margin-top:8px}
+.foot{display:flex;align-items:center;justify-content:space-between;margin-top:12px;padding-top:12px;border-top:1px solid #eef2f1}
+.verified{display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:3px 10px;font:500 11px/1.4 'Inter';
+ background:#f0f9f8;color:#1e5654;box-shadow:inset 0 0 0 1px #b4deda}
+.builder{font-size:12px;color:#5b6b6a}
+</style>
+</head>
+<body>
+ <p class="eyebrow">Home card</p>
+ <div class="card">
+ <div class="photo"><span class="status"><i class="dot"></i>Move-in ready</span></div>
+ <div class="body">
+ <div class="price">$438,990</div>
+ <div class="addr">1420 Marigold Trace, Leander, TX</div>
+ <div class="meta"><span>4 bd</span><span>3 ba</span><span>2,410 sqft</span></div>
+ <div class="foot">
+ <span class="verified">✓ Verified from source</span>
+ <span class="builder">Lennar</span>
+ </div>
+ </div>
+ </div>
+</body>
+</html>
diff --git a/design-system/components/map-legend/index.html b/design-system/components/map-legend/index.html
new file mode 100644
index 0000000..a17777d
--- /dev/null
+++ b/design-system/components/map-legend/index.html
@@ -0,0 +1,33 @@
+<!-- @dsCard group="Components" -->
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>Map legend + filter toggle</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
+body{font-family:'Inter',system-ui,sans-serif;margin:0;background:#f7faf9;padding:32px;color:#0f2b2a}
+.eyebrow{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.18em;color:#226b69;margin-bottom:14px}
+.panel{width:250px;border-radius:16px;background:#fff;border:1px solid rgba(180,222,218,.5);padding:14px;
+ box-shadow:0 1px 2px rgba(16,50,49,.05),0 8px 24px -14px rgba(16,50,49,.2)}
+.grp{font:600 11px/1 'Inter';text-transform:uppercase;letter-spacing:.1em;color:#5b6b6a;margin:4px 0 8px;display:flex;justify-content:space-between}
+.grp a{color:#226b69;text-transform:none;letter-spacing:0;font-weight:600;text-decoration:none}
+.opt{display:flex;align-items:center;gap:9px;padding:5px 4px;font-size:14px;border-radius:8px}
+.opt:hover{background:#f0f9f8}
+.opt input{accent-color:#1e5654;width:15px;height:15px}
+.dot{width:11px;height:11px;border-radius:50%}
+.count{margin-left:auto;font-size:12px;color:#93a3a2}
+</style>
+</head>
+<body>
+ <p class="eyebrow">Map legend & field toggle</p>
+ <div class="panel">
+ <div class="grp"><span>Construction status</span><a href="#">All</a></div>
+ <label class="opt"><input type="checkbox" checked><i class="dot" style="background:#16a34a"></i>Move-in ready<span class="count">990</span></label>
+ <label class="opt"><input type="checkbox" checked><i class="dot" style="background:#f59e0b"></i>Under construction<span class="count">10,995</span></label>
+ <label class="opt"><input type="checkbox" checked><i class="dot" style="background:#3b82f6"></i>Planned<span class="count">117</span></label>
+ </div>
+ <p style="width:250px;font-size:13px;color:#5b6b6a;margin-top:10px">Every field value is an on/off toggle (default all-on, AND across dimensions). Dot colors are the shared construction-status tokens; counts update live.</p>
+</body>
+</html>
diff --git a/design-system/tokens.html b/design-system/tokens.html
new file mode 100644
index 0000000..48d68dd
--- /dev/null
+++ b/design-system/tokens.html
@@ -0,0 +1,75 @@
+<!-- @dsCard group="Foundations" -->
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8" />
+<meta name="viewport" content="width=device-width, initial-scale=1" />
+<title>HomesOnSpec — Foundations</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=Inter:wght@400;500;600&display=swap');
+:root{
+ --brand-50:#f0f9f8;--brand-100:#d9efec;--brand-200:#b4deda;--brand-300:#83c5c0;--brand-400:#4fa5a1;
+ --brand-500:#2f8783;--brand-600:#226b69;--brand-700:#1e5654;--brand-800:#1b4645;--brand-900:#123231;--brand-950:#081e1e;
+ --accent-100:#fef0d0;--accent-300:#f8c464;--accent-400:#f4a934;--accent-500:#ed8f16;--accent-700:#ae5310;--accent-800:#8d4114;
+ --ready:#16a34a;--uc:#f59e0b;--plan:#3b82f6;
+ --sans:'Inter',system-ui,sans-serif;--display:'Fraunces',Georgia,serif;
+}
+body{font-family:var(--sans);margin:0;background:#f7faf9;color:#0f2b2a;padding:32px;line-height:1.4}
+h2{font-family:var(--display);font-weight:600;letter-spacing:-.01em;margin:0 0 4px}
+.eyebrow{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.18em;color:var(--brand-600)}
+section{margin:28px 0}
+.ramp{display:flex;border-radius:12px;overflow:hidden;box-shadow:0 1px 2px rgba(16,50,49,.06)}
+.ramp>div{flex:1;height:56px;display:flex;align-items:flex-end;justify-content:center;padding-bottom:4px;font-size:10px;color:#fff8}
+.type samp{display:block;color:#123231}
+.d1{font-family:var(--display);font-weight:600;font-size:44px;letter-spacing:-.02em;line-height:1.05}
+.d2{font-family:var(--display);font-weight:600;font-size:28px}
+.b1{font-size:16px}.small{font-size:13px;color:#5b6b6a}
+.status{display:flex;gap:18px;margin-top:8px}
+.status span{display:inline-flex;align-items:center;gap:7px;font-size:13px}
+.dot{width:12px;height:12px;border-radius:50%}
+</style>
+</head>
+<body>
+ <p class="eyebrow">HomesOnSpec design system</p>
+ <h2>Foundations</h2>
+ <p class="small">Tokens mirror <code>apps/web/src/app/globals.css</code> — this library and the live app never drift.</p>
+
+ <section>
+ <p class="eyebrow">Brand — teal / pine</p>
+ <div class="ramp">
+ <div style="background:var(--brand-50)">50</div><div style="background:var(--brand-100)">100</div>
+ <div style="background:var(--brand-200)">200</div><div style="background:var(--brand-300)">300</div>
+ <div style="background:var(--brand-400)">400</div><div style="background:var(--brand-500)">500</div>
+ <div style="background:var(--brand-600)">600</div><div style="background:var(--brand-700)">700</div>
+ <div style="background:var(--brand-800)">800</div><div style="background:var(--brand-900)">900</div>
+ <div style="background:var(--brand-950)">950</div>
+ </div>
+ </section>
+
+ <section>
+ <p class="eyebrow">Accent — honey / amber</p>
+ <div class="ramp">
+ <div style="background:var(--accent-100);color:#8884">100</div><div style="background:var(--accent-300);color:#8884">300</div>
+ <div style="background:var(--accent-400)">400</div><div style="background:var(--accent-500)">500</div>
+ <div style="background:var(--accent-700)">700</div><div style="background:var(--accent-800)">800</div>
+ </div>
+ </section>
+
+ <section>
+ <p class="eyebrow">Construction status</p>
+ <div class="status">
+ <span><i class="dot" style="background:var(--ready)"></i>Move-in ready</span>
+ <span><i class="dot" style="background:var(--uc)"></i>Under construction</span>
+ <span><i class="dot" style="background:var(--plan)"></i>Planned</span>
+ </div>
+ </section>
+
+ <section class="type">
+ <p class="eyebrow">Type — Fraunces (display) · Inter (body)</p>
+ <samp class="d1">Every new home.</samp>
+ <samp class="d2">Every builder. One search.</samp>
+ <samp class="b1">Move-in-ready and under-construction homes, verified from the source.</samp>
+ <samp class="small">13,414 verified homes · 30 builders · updated continuously</samp>
+ </section>
+</body>
+</html>
← 678cf48 Design system iter-1: @theme token layer (brand/accent/statu
·
back to Homesonspec
·
Design system iter-2: reskin /map explorer panel + /search c 832a5c0 →