Files
whynot-design/designbook/preview/page-beta-invitation.html
tegwick 0d688ca94a feat(designbook): technology-neutral IR + stack-adapter pipeline (WHYNOT-WP-0002 T01-T06)
Author the design language once in the canonical React designbook and project it
one-way onto each stack: React -> designbook/ -> ir/ -> adapters/<stack>/.

Phase 0 — contracts & governance (T01-T03):
- ir/SCHEMA.md + ir/schema/{component,tokens}.schema.json — neutral IR contract
  (W3C DTCG tokens; React prop -> HTML attribute mapping; non-portable props flagged).
- adapters/ADAPTER_CONTRACT.md — inputs, drift-report + parity-result shapes,
  idempotency rules, CI exit codes (0 ok / 2 usage / 3 drift / 4 parity / 5 internal).
- .claude/rules/designbook-propagation.md + DesignSystemIntroduction.md §5.1 —
  one-way directionality + drift-resolution workflow.

T04 — canonical React designbook + the missing pull tool:
- The bundled /design-sync skill only PUSHES repo->cloud; it cannot populate
  designbook/. Added scripts/designbook_pull.py + `make designbook-pull`, which drives
  the local claude binary headless (acceptEdits) so DesignSync fetch+write runs in a
  subprocess (contents never hit the orchestrator's context). Pulled 44 files;
  excludes the _whynot-design-seed/ self-copy. Corrected the docs that wrongly called
  /design-sync the pull.

T05 — IR extractor (scripts/ir-extract.mjs + `make ir`):
- ir/tokens.json (80 tokens, DTCG, var() -> {ref} alias resolution); ir/components/*.json
  (10 contracts parsed from .jsx signatures: enum/boolean/number inference, prop->attr
  map, style/callback marked non-portable); ir/exemplars/*.

T06 — Lit token adapter (adapters/lit/ + `make adapt-lit`):
- Full-gen tokens into src/styles/colors_and_type.css :root (marker-bounded, idempotent
  no-op on re-run; hand-authored type CSS preserved).

NOTE: token regen synced Lit to canonical React — fonts IBM Plex -> system stacks and 8
status tokens added. This is a VISUAL change: review and run `pnpm test:visual:update`
before merge. Remaining: T07 scaffold+drift, T08 parity, T09 runbook, T10 2nd-adapter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 12:36:24 +02:00

105 lines
5.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<!-- @dsCard group="Pages" name="Pages · Closed-beta invitation" subtitle="Invitation-only · seats, dates, accept / decline" viewport="1280x860" -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>You're invited · whynot closed beta</title>
<link rel="icon" href="../assets/whynot-logo.png">
<link rel="stylesheet" href="../colors_and_type.css">
<style>
html, body { margin: 0; min-height: 100%; background: var(--paper); color: var(--fg-1); }
.page { min-height: 100vh; display: flex; flex-direction: column; }
.nav { height: 60px; flex: none; display: flex; align-items: center; gap: 16px; padding: 0 40px; border-bottom: 1px solid var(--line); }
.nav .brand { display: flex; align-items: center; gap: 10px; }
.nav .brand img { width: 22px; height: 22px; }
.nav .brand .nm { font: 500 15px var(--ff-sans); letter-spacing: -0.01em; }
.nav .brand .slug { font: 400 12px var(--ff-mono); color: var(--fg-3); }
.nav .pill { margin-left: auto; font: 500 11px/1 var(--ff-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg-3); border: 1px solid var(--line); border-radius: 999px; padding: 6px 11px; }
.wrap {
flex: 1; display: flex; align-items: center; justify-content: center;
padding: 48px 24px;
background:
linear-gradient(to right, var(--line-soft) 1px, transparent 1px) 0 0 / 28px 28px,
linear-gradient(to bottom, var(--line-soft) 1px, transparent 1px) 0 0 / 28px 28px,
var(--paper-2);
}
.invite {
width: 100%; max-width: 560px; background: var(--paper);
border: 1px solid var(--line-strong); border-radius: var(--r-3);
padding: 40px 44px 36px; position: relative;
}
.stamp {
position: absolute; top: -14px; right: 28px;
background: var(--hi); color: var(--hi-ink);
font: 500 10px/1 var(--ff-mono); letter-spacing: 0.12em; text-transform: uppercase;
padding: 7px 12px 5px; transform: rotate(-2deg);
}
.invite .eyebrow { font: 500 11px/1 var(--ff-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-3); }
.invite h1 { font: 400 30px/1.2 var(--ff-sans); letter-spacing: -0.02em; margin: 12px 0 0; max-width: 18ch; }
.invite .lede { font: 400 16px/1.6 var(--ff-sans); color: var(--fg-2); margin: 14px 0 0; max-width: 46ch; }
.specs { margin: 28px 0 0; border-top: 1px solid var(--line); }
.spec { display: grid; grid-template-columns: 150px 1fr; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--line-soft); align-items: baseline; }
.spec .k { font: 500 11px/1.4 var(--ff-mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--fg-3); }
.spec .v { font: 400 14px/1.5 var(--ff-sans); color: var(--fg-1); }
.spec .v .mono { font-family: var(--ff-mono); }
.actions { display: flex; align-items: center; gap: 12px; margin-top: 28px; }
.btn { font: 500 14px var(--ff-sans); padding: 12px 20px; border-radius: var(--r-2); border: 1px solid var(--ink); background: var(--ink); color: var(--paper); cursor: pointer; }
.btn:hover { background: var(--ink-2); }
.btn.ghost { background: transparent; color: var(--fg-2); border-color: transparent; padding: 12px 10px; }
.btn.ghost:hover { color: var(--fg-1); background: var(--paper-3); }
.actions .seats { margin-left: auto; font: 400 11px var(--ff-mono); color: var(--fg-3); }
.note { margin-top: 24px; padding-top: 18px; border-top: 1px solid var(--line-soft); font: 400 12px/1.6 var(--ff-mono); color: var(--fg-3); }
.note b { color: var(--fg-2); font-weight: 500; }
.footer { flex: none; padding: 18px 40px; border-top: 1px solid var(--line); display: flex; gap: 14px; font: 400 11px var(--ff-mono); color: var(--fg-3); }
.footer .sp { margin-left: auto; }
</style>
</head>
<body>
<div class="page">
<nav class="nav">
<div class="brand"><img src="../assets/whynot-logo.png" alt=""><span class="nm">whynot</span><span class="slug">/ betas</span></div>
<span class="pill">Closed beta · invitation only</span>
</nav>
<div class="wrap">
<div class="invite">
<span class="stamp">Invitation · WNO-021</span>
<span class="eyebrow">Youre invited</span>
<h1>Concierge prototype triage</h1>
<p class="lede">A one-hour call where we take one of your half-formed ideas and turn it into a testable prototype card — learning question, smallest useful test, and all.</p>
<div class="specs">
<div class="spec"><span class="k">Learning question</span><span class="v">Will three founders pay a listed price for a single triage call?</span></div>
<div class="spec"><span class="k">What you do</span><span class="v">Bring one idea. Leave with a prototype card and a next step.</span></div>
<div class="spec"><span class="k">Seats</span><span class="v">5 · <span class="mono">2 remaining</span></span></div>
<div class="spec"><span class="k">Window</span><span class="v"><span class="mono">2026-04-01 → 2026-04-14</span></span></div>
<div class="spec"><span class="k">Cost</span><span class="v">Listed price. No refunds, no obligations after.</span></div>
</div>
<div class="actions">
<button class="btn">Accept invitation</button>
<button class="btn ghost">Not now</button>
<span class="seats">Expires in 6 days</span>
</div>
<p class="note"><b>Invitation only.</b> This is a prototype, not a product — it may be parked after the beta regardless of how it goes. Accepting reserves a seat; it is not a commitment to continue.</p>
</div>
</div>
<footer class="footer">
<span>whynot · betas</span>
<span>·</span>
<span>BETA_MODEL.md</span>
<span class="sp">try($idea) until success;</span>
</footer>
</div>
</body>
</html>