diff --git a/AGENTS.md b/AGENTS.md index 3a9d95a..20f3b74 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -25,6 +25,7 @@ its guide** — see the index below. - Before building, bumping the version, or editing the StartOS wrapper, read `docs/guides/startos-packaging.md`. - Before editing the admin SPA (`web/index.html`), read `docs/guides/admin-ui.md`. - Before editing public site/docs copy, read `docs/guides/website-copy.md`. +- **Before building or changing any user-facing UI (landing, docs, admin SPA), read `design/DESIGN.md` and `design/tokens.tokens.json` and conform to them** — the brand contract; pull colors/type/space/radii/shadows from the tokens, never hardcode off-scale values. - Before adding/altering tests or relying on lint/CI, read `docs/guides/testing.md`. ## Build / test / run (quick ref) @@ -50,7 +51,7 @@ licensing-service-startos/ daemon + StartOS wrapper (s9pk package source) keysat-xyz-landing/ keysat-docs/ keysat-registry-landing/ public sites → guides/website-copy.md licensing-client-{rust,ts,python,go}/ the four SDK source repos activate-license-template/ Tauri desktop template for license activation -keysat-design-system/ design tokens / brand assets +design/ design contract (DESIGN.md + tokens.tokens.json) + brand/ assets; original Claude Design system archived in design/_imports/ plans/ design specs (multi-provider-payment-model.md, keysat-smtp-emails.md) tests/crosscheck/ cross-language LIC1 verifier → guides/crypto-wire-format.md ``` diff --git a/ROADMAP.md b/ROADMAP.md index 9b622a4..d12e6ff 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -24,3 +24,36 @@ Longer-term backlog. Near-term state lives in `AGENTS.md` → Current state. - Re-test `KEYSAT_INTEGRATION.md` against a fresh downstream app to confirm a clean one-shot SDK integration. - End-to-end Zaprite sandbox pass on the multi-merchant-profile webhook routing before relying on it in production. + +## Design (contract conformance) + +The brand contract now lives in `design/DESIGN.md` + `design/tokens.tokens.json` (distilled +2026-06-16 from the prior Claude Design system, now archived in `design/_imports/`). A +`design-checker` audit (2026-06-16) found high fidelity overall, with these items where the +**code contradicts the contract's stated rules** or bypasses the token scale: + +**Blockers (code violates a named "never" rule):** +- Gold used as an actionable *fill* (contract: gold is accent/border only, never a fill). + (a) admin SPA `.featured-pill-toggle.on` → `web/index.html:418`; (b) admin sidebar + upgrade CTA `#tier-banner-cta` → `web/index.html:537-542`. Fix to navy-fill or + gold-border/text. +- Primary buy CTA uses pill radius `999px` (contract: buttons are `r-md` 8px; pill is + badges-only) — `keysat-xyz-landing/index.html:384-385`. Set to 8px. + +**Structural (headline):** +- All four surfaces inline their own copy of the CSS variables instead of importing the + canonical `design/brand/palette.css` (landing :33-56, registry :11-22, docs.css :7-21, + admin :9-25). Copies are currently exact but one edit from drift. Consolidate onto + `palette.css`. + +**Token gaps / drift (decide: tokenize the as-built value, or snap to an existing token):** +- `14px` card radius used throughout the marketing landing — not a token (between `r-lg` 12 + and `r-xl` 18). Snap to a token or add one. +- Wordmark letter-spacing is `0.30em` (landing) vs `0.28em` (docs/admin) and has no token — + pick one value, add a `letterSpacing.wordmark` token. +- Semantic badge *text* colors (`#205c47`/`#7a5814`/`#8a2828`) are darker one-offs with no + token — add `semantic.*-text` tokens or reference existing ones. +- Syntax-highlight colors hardcoded as hex (`#d4b985`=gold-400, `#a6b7cf`=navy-300) — switch + to `var()`. One admin hex `#f6f1e7` isn't a token (closest cream-50/100) — reconcile. +- Sticky-header backdrop on docs/admin (`blur(10px)`/`blur(8px)`) diverges from the contract's + `blur(12px)` — align if a single header treatment is wanted. diff --git a/design/DESIGN.md b/design/DESIGN.md new file mode 100644 index 0000000..2daf32d --- /dev/null +++ b/design/DESIGN.md @@ -0,0 +1,142 @@ +--- +project: keysat +tagline: Software licensing for Bitcoin creators +source: design/_imports/2026-06-16-claude-design-system/ (Claude Design output, May 2025) +tokens: design/tokens.tokens.json +canonical_css: design/brand/palette.css +last_distilled: 2026-06-16 +--- + +# Keysat — design contract + +> The durable, vendor-neutral brand brief. Any agent building or changing a user-facing +> surface (the marketing landing, the docs site, the creator admin SPA) reads this and +> `design/tokens.tokens.json` first and conforms to them. Token *values* live in the tokens +> file; this document is the *intent* and the rules. Distilled from a prior Claude Design +> system (now in `design/_imports/`). + +## 1. Visual theme + +Navy ink on cream paper, with a gold accent that whispers. The reference objects are a +**certificate of authenticity, a vault deed, a hand-numbered print** — classical trust +signaling crossed with modern indie-software practicality. Restrained, archival, precise; +**modern in interaction, classical in composition.** The identity is anchored by the logo: a +deep-navy key crossing a Bitcoin "B" bow, on cream paper with a gold inner border. The brand +reads as **printed, not liquid** — solid surfaces over glass and gradients. + +## 2. Color palette + +Values in `tokens.tokens.json`. Roles: + +- **Navy is the primary brand color.** `navy-800` (`#1E3A5F`) is the wordmark color and + dominant ink — primary buttons, headings, key chrome. Full scale `navy-950 → navy-50`. +- **Cream is the page background.** `cream-100` (`#F5F1E8`) default; `cream-50` (`#FBF9F2`) + for elevated paper. **Pure white (`#FFFFFF`)** is reserved for forms, tables, and code + blocks where contrast matters. +- **Gold (`gold-500`, `#BFA068`) is the accent, used sparingly** — eyebrow labels, dividers, + the inner stroke of premium cards, a verified-badge highlight. **Never a primary button + color.** +- **Ink scale (`ink-900 → ink-300`)** handles body text, secondary copy, disabled states. +- **Semantic:** success `#2D7A5F`, warning `#B8861F`, danger `#B23A3A`, info = `navy-700`, + each with a tinted `-bg`. +- Borders are **alpha navy**, not solid lines: `border-1` 12%, `border-2` 20%, `border-3` 35%. + +## 3. Typography + +- **Display — Manrope** (`font-display`): geometric sans, mirrors the wordmark. h1–h4, large + numerals, the wordmark. Weights 400–700 (500 for h1/h2, 600 for h3/h4). *Note: the original + design-system README named "Archivo" as a placeholder substitution, but the shipped CSS and + every live surface use Manrope — Manrope is canonical. If a licensed display face is ever + supplied, swap `font.display` in the tokens and remove the Google Fonts import.* +- **Body — Inter** (`font-body`): humanist sans for prose, UI labels, form fields. Stylistic + sets `ss01` + `cv11`. +- **Mono — JetBrains Mono** (`font-mono`): license keys, code samples, API responses, tx IDs. +- **Type scale** is the `fs-*` tokens (`display-xl` clamp 56–88px down to `meta` 12px). + Headings track tight (`-0.02em`); eyebrows track wide (`0.18em`), uppercase. +- **Casing:** sentence case for buttons/menus/headings ("Create a license"); ALL CAPS + wide + tracking only for eyebrow labels above sections, sparingly. Proper nouns capitalized + (Keysat, Start9, StartOS, BTCPay, Bitcoin, Lightning, Ed25519). +- **Identifiers:** license keys monospace, hyphen-grouped (`KS-9F2A-7C41-XK22-6D8E`); keys/ + hashes ellipsized middle (`mz7q8…h3k2p`); amounts default to **sats** under 0.01 BTC. + +## 4. Component styling + +- **Buttons** — radius `r-md` (8px). Primary: `navy-800` bg, `cream-50` text; hover `navy-900`, + press `navy-950` + 1px translate-down (no scale). Secondary: `cream-50` bg, alpha-navy + border; hover `cream-200`. Ghost: transparent; hover `rgba(14,31,51,0.05)`. **Gold is a + text/border treatment only, never a primary button fill.** Danger: red text + faint red + border. +- **Cards** — radius `r-lg` (12px), on cream with a hairline `border-1` and `shadow-sm`. + Premium/featured cards get a **1px gold inner stroke** (`gold-500`) + `shadow-md`. +- **Badges** — pill (`r-pill`), tinted semantic bg + matching text; gold/neutral = transparent + with a gold border. +- **Forms** — white bg, alpha-navy border, radius ~7px; focus = navy border + `ring-focus` + halo. Monospace variant for keys. +- **Code blocks** — `navy-950` bg, `cream-50` text, `r-lg`, JetBrains Mono; gold/cream syntax. +- **Icons — Lucide**, stroke 1.75px, 16/20/24px. **No emoji in product UI. No PNG icons** (the + logo mark is SVG; only the source thumbnail is PNG). The logo mark is never recolored — + navy, or cream on dark surfaces. + +## 5. Layout + +- **4px base grid**, spacing tokens `sp-1` (4px) → `sp-12` (128px). Use the scale; don't mint + magic numbers. +- Marketing pages **breathe** — sections often `sp-11` (96px) apart. Dashboard density is + moderate: table rows ~52px, card padding `sp-6` (24px). +- Max content width on marketing ~1200px; reading width for prose/docs ~680px. +- **Backgrounds are cream with a subtle grain** (the `paper-texture` utility — two radial-dot + grids at ~2.5% opacity), never flat color. Section bands alternate cream → cream-200 → + cream-50 → navy-950 (dark CTAs/footers). + +## 6. Depth / elevation + +A **paper-shadow** system, not a glassy one. `shadow-xs`/`sm` for resting cards; `shadow-md` +for elevated/premium cards; `shadow-lg` for popovers/menus; `shadow-xl` for modals/command +palettes. `shadow-inset` gives buttons subtle paper relief. Elevation comes from **shadow, +not heavy borders**. Transparency/blur is rare — acceptable only for the sticky marketing +header (`blur(12px)` over `rgba(245,241,232,0.85)`) and the modal scrim (`rgba(14,31,51,0.55)`). + +## 7. Do's and don'ts + +**Do** +- Lead copy with *what the creator owns* — the signing key, the customer list, the payment + rails. Sovereignty-first is the brand's center of gravity. +- Keep gold rare and accenting; keep motion quiet (200ms standard, 120ms hover). +- Use solid surfaces, restrained radii, hairline alpha borders, the paper grain. +- Link a one-sentence definition the first time a term appears (Ed25519, BTCPay webhook, + `.s9pk`). + +**Don't** +- **No hype words:** revolutionary, seamless, unlock, supercharge, leverage, ecosystem, + journey, paradigm, game-changing. +- **No emoji** in product UI; **no PNG icons**; **no Bitcoin orange** in the UI (navy/cream + stands alone); no blue/purple gradients, no glassmorphism. +- **Gold is never a primary button fill.** Radii never exceed ~18px (`r-xl`) for surfaces — + no 24px+ rounding (reads as a consumer fintech app, which Keysat is not). +- No spring physics, no scale-up on hover (cards move at most 1px; buttons darken, not grow). +- Never remove focus rings. + +## 8. Responsive behavior + +Breakpoints in use: **980px** (grids collapse), **720px** (sidebar → slide-in drawer), +**640px** (phone: tighter chrome, single column). Container padding steps 32px desktop → 20px +tablet → 14px phone. Marketing is full-width hero + stacked sections; docs is a 3-column +(sidebar | prose | TOC) collapsing to single column at 980px; admin is a 240px sticky sidebar ++ main, sidebar drawering at 720px. + +## 9. Agent prompt guide + +When building or changing a Keysat UI: + +- **Pull every color, size, space, radius, and shadow from `design/tokens.tokens.json`** (or a + CSS custom property derived from it — see `design/brand/palette.css`). Do not hardcode hex or + px values that bypass the scale. +- Match the **existing surface** you're editing (landing / docs / admin) — they share the token + set; keep them consistent rather than introducing a new look. +- Default to **navy primary buttons, cream pages, gold-as-accent-only**, paper shadows, Lucide + icons, sentence-case labels, no emoji. +- If a needed value genuinely isn't in the tokens, **add it to the tokens file** (and ideally + `palette.css`) rather than inlining a one-off — keep the contract the single source of truth. +- Known debt (see ROADMAP): the three surfaces currently inline their own copy of the + variables. Prefer importing `design/brand/palette.css`; when you touch a surface, move it + toward that shared source rather than perpetuating a private copy. diff --git a/keysat-design-system/README.md b/design/_imports/2026-06-16-claude-design-system/README.md similarity index 100% rename from keysat-design-system/README.md rename to design/_imports/2026-06-16-claude-design-system/README.md diff --git a/keysat-design-system/SKILL.md b/design/_imports/2026-06-16-claude-design-system/SKILL.md similarity index 100% rename from keysat-design-system/SKILL.md rename to design/_imports/2026-06-16-claude-design-system/SKILL.md diff --git a/keysat-design-system/assets/bitcoin-mark.svg b/design/_imports/2026-06-16-claude-design-system/assets/bitcoin-mark.svg similarity index 100% rename from keysat-design-system/assets/bitcoin-mark.svg rename to design/_imports/2026-06-16-claude-design-system/assets/bitcoin-mark.svg diff --git a/keysat-design-system/assets/favicon.svg b/design/_imports/2026-06-16-claude-design-system/assets/favicon.svg similarity index 100% rename from keysat-design-system/assets/favicon.svg rename to design/_imports/2026-06-16-claude-design-system/assets/favicon.svg diff --git a/keysat-design-system/assets/keysat-lockup.svg b/design/_imports/2026-06-16-claude-design-system/assets/keysat-lockup.svg similarity index 100% rename from keysat-design-system/assets/keysat-lockup.svg rename to design/_imports/2026-06-16-claude-design-system/assets/keysat-lockup.svg diff --git a/keysat-design-system/assets/keysat-mark-mono.svg b/design/_imports/2026-06-16-claude-design-system/assets/keysat-mark-mono.svg similarity index 100% rename from keysat-design-system/assets/keysat-mark-mono.svg rename to design/_imports/2026-06-16-claude-design-system/assets/keysat-mark-mono.svg diff --git a/keysat-design-system/assets/keysat-mark-reverse.svg b/design/_imports/2026-06-16-claude-design-system/assets/keysat-mark-reverse.svg similarity index 100% rename from keysat-design-system/assets/keysat-mark-reverse.svg rename to design/_imports/2026-06-16-claude-design-system/assets/keysat-mark-reverse.svg diff --git a/keysat-design-system/assets/keysat-mark.svg b/design/_imports/2026-06-16-claude-design-system/assets/keysat-mark.svg similarity index 100% rename from keysat-design-system/assets/keysat-mark.svg rename to design/_imports/2026-06-16-claude-design-system/assets/keysat-mark.svg diff --git a/keysat-design-system/colors_and_type.css b/design/_imports/2026-06-16-claude-design-system/colors_and_type.css similarity index 100% rename from keysat-design-system/colors_and_type.css rename to design/_imports/2026-06-16-claude-design-system/colors_and_type.css diff --git a/keysat-design-system/explorations/design-canvas.jsx b/design/_imports/2026-06-16-claude-design-system/explorations/design-canvas.jsx similarity index 100% rename from keysat-design-system/explorations/design-canvas.jsx rename to design/_imports/2026-06-16-claude-design-system/explorations/design-canvas.jsx diff --git a/keysat-design-system/explorations/logo-directions-v2.html b/design/_imports/2026-06-16-claude-design-system/explorations/logo-directions-v2.html similarity index 100% rename from keysat-design-system/explorations/logo-directions-v2.html rename to design/_imports/2026-06-16-claude-design-system/explorations/logo-directions-v2.html diff --git a/keysat-design-system/explorations/logo-directions.html b/design/_imports/2026-06-16-claude-design-system/explorations/logo-directions.html similarity index 100% rename from keysat-design-system/explorations/logo-directions.html rename to design/_imports/2026-06-16-claude-design-system/explorations/logo-directions.html diff --git a/keysat-design-system/explorations/type-directions.html b/design/_imports/2026-06-16-claude-design-system/explorations/type-directions.html similarity index 100% rename from keysat-design-system/explorations/type-directions.html rename to design/_imports/2026-06-16-claude-design-system/explorations/type-directions.html diff --git a/keysat-design-system/preview/badges.html b/design/_imports/2026-06-16-claude-design-system/preview/badges.html similarity index 100% rename from keysat-design-system/preview/badges.html rename to design/_imports/2026-06-16-claude-design-system/preview/badges.html diff --git a/keysat-design-system/preview/brand-logo.html b/design/_imports/2026-06-16-claude-design-system/preview/brand-logo.html similarity index 100% rename from keysat-design-system/preview/brand-logo.html rename to design/_imports/2026-06-16-claude-design-system/preview/brand-logo.html diff --git a/keysat-design-system/preview/buttons.html b/design/_imports/2026-06-16-claude-design-system/preview/buttons.html similarity index 100% rename from keysat-design-system/preview/buttons.html rename to design/_imports/2026-06-16-claude-design-system/preview/buttons.html diff --git a/keysat-design-system/preview/cards.html b/design/_imports/2026-06-16-claude-design-system/preview/cards.html similarity index 100% rename from keysat-design-system/preview/cards.html rename to design/_imports/2026-06-16-claude-design-system/preview/cards.html diff --git a/keysat-design-system/preview/colors-cream-gold.html b/design/_imports/2026-06-16-claude-design-system/preview/colors-cream-gold.html similarity index 100% rename from keysat-design-system/preview/colors-cream-gold.html rename to design/_imports/2026-06-16-claude-design-system/preview/colors-cream-gold.html diff --git a/keysat-design-system/preview/colors-navy.html b/design/_imports/2026-06-16-claude-design-system/preview/colors-navy.html similarity index 100% rename from keysat-design-system/preview/colors-navy.html rename to design/_imports/2026-06-16-claude-design-system/preview/colors-navy.html diff --git a/keysat-design-system/preview/colors-semantic.html b/design/_imports/2026-06-16-claude-design-system/preview/colors-semantic.html similarity index 100% rename from keysat-design-system/preview/colors-semantic.html rename to design/_imports/2026-06-16-claude-design-system/preview/colors-semantic.html diff --git a/keysat-design-system/preview/forms.html b/design/_imports/2026-06-16-claude-design-system/preview/forms.html similarity index 100% rename from keysat-design-system/preview/forms.html rename to design/_imports/2026-06-16-claude-design-system/preview/forms.html diff --git a/keysat-design-system/preview/license-keys.html b/design/_imports/2026-06-16-claude-design-system/preview/license-keys.html similarity index 100% rename from keysat-design-system/preview/license-keys.html rename to design/_imports/2026-06-16-claude-design-system/preview/license-keys.html diff --git a/keysat-design-system/preview/radii.html b/design/_imports/2026-06-16-claude-design-system/preview/radii.html similarity index 100% rename from keysat-design-system/preview/radii.html rename to design/_imports/2026-06-16-claude-design-system/preview/radii.html diff --git a/keysat-design-system/preview/shadows.html b/design/_imports/2026-06-16-claude-design-system/preview/shadows.html similarity index 100% rename from keysat-design-system/preview/shadows.html rename to design/_imports/2026-06-16-claude-design-system/preview/shadows.html diff --git a/keysat-design-system/preview/spacing-scale.html b/design/_imports/2026-06-16-claude-design-system/preview/spacing-scale.html similarity index 100% rename from keysat-design-system/preview/spacing-scale.html rename to design/_imports/2026-06-16-claude-design-system/preview/spacing-scale.html diff --git a/keysat-design-system/preview/type-body-mono.html b/design/_imports/2026-06-16-claude-design-system/preview/type-body-mono.html similarity index 100% rename from keysat-design-system/preview/type-body-mono.html rename to design/_imports/2026-06-16-claude-design-system/preview/type-body-mono.html diff --git a/keysat-design-system/preview/type-display.html b/design/_imports/2026-06-16-claude-design-system/preview/type-display.html similarity index 100% rename from keysat-design-system/preview/type-display.html rename to design/_imports/2026-06-16-claude-design-system/preview/type-display.html diff --git a/keysat-design-system/ui_kits/dashboard/README.md b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/README.md similarity index 100% rename from keysat-design-system/ui_kits/dashboard/README.md rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/README.md diff --git a/keysat-design-system/ui_kits/dashboard/dash.css b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/dash.css similarity index 100% rename from keysat-design-system/ui_kits/dashboard/dash.css rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/dash.css diff --git a/keysat-design-system/ui_kits/dashboard/index.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/index.html similarity index 100% rename from keysat-design-system/ui_kits/dashboard/index.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/index.html diff --git a/keysat-design-system/ui_kits/dashboard/license-detail.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/license-detail.html similarity index 100% rename from keysat-design-system/ui_kits/dashboard/license-detail.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/license-detail.html diff --git a/keysat-design-system/ui_kits/dashboard/licenses.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/licenses.html similarity index 100% rename from keysat-design-system/ui_kits/dashboard/licenses.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/licenses.html diff --git a/keysat-design-system/ui_kits/dashboard/new-product.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/new-product.html similarity index 100% rename from keysat-design-system/ui_kits/dashboard/new-product.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/new-product.html diff --git a/keysat-design-system/ui_kits/dashboard/signin.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/signin.html similarity index 100% rename from keysat-design-system/ui_kits/dashboard/signin.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/dashboard/signin.html diff --git a/keysat-design-system/ui_kits/docs/README.md b/design/_imports/2026-06-16-claude-design-system/ui_kits/docs/README.md similarity index 100% rename from keysat-design-system/ui_kits/docs/README.md rename to design/_imports/2026-06-16-claude-design-system/ui_kits/docs/README.md diff --git a/keysat-design-system/ui_kits/docs/index.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/docs/index.html similarity index 100% rename from keysat-design-system/ui_kits/docs/index.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/docs/index.html diff --git a/keysat-design-system/ui_kits/marketing/README.md b/design/_imports/2026-06-16-claude-design-system/ui_kits/marketing/README.md similarity index 100% rename from keysat-design-system/ui_kits/marketing/README.md rename to design/_imports/2026-06-16-claude-design-system/ui_kits/marketing/README.md diff --git a/keysat-design-system/ui_kits/marketing/index.html b/design/_imports/2026-06-16-claude-design-system/ui_kits/marketing/index.html similarity index 100% rename from keysat-design-system/ui_kits/marketing/index.html rename to design/_imports/2026-06-16-claude-design-system/ui_kits/marketing/index.html diff --git a/keysat-design-system/uploads/index.html b/design/_imports/2026-06-16-claude-design-system/uploads/index.html similarity index 100% rename from keysat-design-system/uploads/index.html rename to design/_imports/2026-06-16-claude-design-system/uploads/index.html diff --git a/keysat-design-system/uploads/keysat-thumbnail.png b/design/_imports/2026-06-16-claude-design-system/uploads/keysat-thumbnail.png similarity index 100% rename from keysat-design-system/uploads/keysat-thumbnail.png rename to design/_imports/2026-06-16-claude-design-system/uploads/keysat-thumbnail.png diff --git a/design/brand/bitcoin-mark.svg b/design/brand/bitcoin-mark.svg new file mode 100644 index 0000000..cd43f29 --- /dev/null +++ b/design/brand/bitcoin-mark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/design/brand/favicon.svg b/design/brand/favicon.svg new file mode 100644 index 0000000..31f1365 --- /dev/null +++ b/design/brand/favicon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/design/brand/keysat-lockup.svg b/design/brand/keysat-lockup.svg new file mode 100644 index 0000000..41d46c7 --- /dev/null +++ b/design/brand/keysat-lockup.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + KEYSAT + \ No newline at end of file diff --git a/design/brand/keysat-mark-mono.svg b/design/brand/keysat-mark-mono.svg new file mode 100644 index 0000000..472cb08 --- /dev/null +++ b/design/brand/keysat-mark-mono.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/design/brand/keysat-mark-reverse.svg b/design/brand/keysat-mark-reverse.svg new file mode 100644 index 0000000..0880e15 --- /dev/null +++ b/design/brand/keysat-mark-reverse.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/design/brand/keysat-mark.svg b/design/brand/keysat-mark.svg new file mode 100644 index 0000000..826dea1 --- /dev/null +++ b/design/brand/keysat-mark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/design/brand/palette.css b/design/brand/palette.css new file mode 100644 index 0000000..25f197b --- /dev/null +++ b/design/brand/palette.css @@ -0,0 +1,285 @@ +/* ============================================================ + Keysat — palette.css (CANONICAL design tokens as CSS custom properties) + "Software Licensing for Bitcoin Creators" + Navy + cream, paper texture, classical type. + + Single canonical stylesheet, derived from design/tokens.tokens.json. + Surfaces (landing, docs, admin SPA) should @import or inline THIS file + rather than keep private copies — see the "shared token source" item in + ROADMAP.md. Keep this and the tokens JSON in sync; never fork a one-off copy. + ============================================================ */ + +@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap'); + +:root { + /* ---------- Brand Colors ---------- */ + /* Primary navy — pulled from the wordmark */ + --navy-950: #0E1F33; + --navy-900: #142A47; + --navy-800: #1E3A5F; /* core brand navy */ + --navy-700: #2A4A75; + --navy-600: #3A5C8A; + --navy-500: #5074A1; + --navy-400: #7892B8; + --navy-300: #A6B7CF; + --navy-200: #CBD5E2; + --navy-100: #E4EAF1; + --navy-50: #F2F5F9; + + /* Cream / paper — the background tone of the logo card */ + --cream-50: #FBF9F2; + --cream-100: #F5F1E8; /* core cream */ + --cream-200: #EDE7D7; + --cream-300: #E1D8C0; + --cream-400: #C9BC9A; + + /* Gold / tan — the inner key border */ + --gold-700: #8A6F3D; + --gold-600: #A88652; + --gold-500: #BFA068; /* core gold accent */ + --gold-400: #D4B985; + --gold-300: #E5CFA5; + --gold-200: #F0E2C5; + + /* Ink — dark text */ + --ink-900: #0E1F33; + --ink-700: #2C3E54; + --ink-500: #5A6B7F; + --ink-400: #7E8C9D; + --ink-300: #A4AEBB; + + /* Semantic */ + --success: #2D7A5F; + --success-bg: #E3F0EA; + --warning: #B8861F; + --warning-bg: #F7EFD7; + --danger: #B23A3A; + --danger-bg: #F4E0E0; + --info: var(--navy-700); + --info-bg: var(--navy-100); + + /* ---------- Semantic surface tokens ---------- */ + --bg-page: var(--cream-100); /* default page bg */ + --bg-paper: var(--cream-50); /* lighter paper */ + --bg-elev: #FFFFFF; /* elevated surface (cards on cream) */ + --bg-inverse: var(--navy-900); /* dark surface */ + --bg-tint: var(--cream-200); /* tinted band/section */ + + --fg-1: var(--ink-900); /* primary text */ + --fg-2: var(--ink-700); /* secondary text */ + --fg-3: var(--ink-500); /* tertiary / meta */ + --fg-4: var(--ink-400); /* disabled / hint */ + --fg-on-navy: var(--cream-50); + --fg-on-gold: var(--navy-900); + + --border-1: rgba(14, 31, 51, 0.12); /* hairline on cream */ + --border-2: rgba(14, 31, 51, 0.20); /* card border */ + --border-3: rgba(14, 31, 51, 0.35); /* focus / strong */ + --border-on-navy: rgba(245, 241, 232, 0.18); + + --accent: var(--navy-800); + --accent-hover: var(--navy-900); + --accent-press: var(--navy-950); + --accent-soft: var(--navy-100); + + --gold: var(--gold-500); + --gold-hover: var(--gold-600); + + /* ---------- Type families ---------- */ + --font-display: 'Manrope', 'Helvetica Neue', Arial, sans-serif; + --font-body: 'Inter', 'Helvetica Neue', Arial, sans-serif; + --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace; + + /* ---------- Type scale ---------- */ + --fs-display-xl: clamp(56px, 6vw, 88px); + --fs-display: clamp(40px, 4.5vw, 64px); + --fs-h1: 44px; + --fs-h2: 32px; + --fs-h3: 24px; + --fs-h4: 20px; + --fs-h5: 17px; + --fs-body-lg: 18px; + --fs-body: 15px; + --fs-body-sm: 13.5px; + --fs-meta: 12px; + --fs-mono: 13px; + + /* ---------- Line heights ---------- */ + --lh-display: 1.02; + --lh-heading: 1.15; + --lh-body: 1.55; + --lh-tight: 1.25; + + /* ---------- Letter spacing ---------- */ + --tracking-tight: -0.02em; + --tracking-normal: 0; + --tracking-wide: 0.04em; + --tracking-eyebrow: 0.18em; + + /* ---------- Spacing (4px base) ---------- */ + --sp-1: 4px; + --sp-2: 8px; + --sp-3: 12px; + --sp-4: 16px; + --sp-5: 20px; + --sp-6: 24px; + --sp-7: 32px; + --sp-8: 40px; + --sp-9: 56px; + --sp-10: 72px; + --sp-11: 96px; + --sp-12: 128px; + + /* ---------- Radii ---------- */ + --r-xs: 3px; + --r-sm: 5px; + --r-md: 8px; + --r-lg: 12px; + --r-xl: 18px; + --r-2xl: 24px; + --r-pill: 999px; + + /* ---------- Shadows ---------- */ + /* Quiet, layered shadows — paper, not glassy */ + --shadow-xs: 0 1px 1px rgba(14,31,51,0.04); + --shadow-sm: 0 1px 2px rgba(14,31,51,0.06), 0 1px 1px rgba(14,31,51,0.03); + --shadow-md: 0 2px 4px rgba(14,31,51,0.06), 0 4px 12px rgba(14,31,51,0.06); + --shadow-lg: 0 4px 8px rgba(14,31,51,0.07), 0 12px 32px rgba(14,31,51,0.10); + --shadow-xl: 0 8px 16px rgba(14,31,51,0.10), 0 24px 64px rgba(14,31,51,0.14); + --shadow-inset: inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -1px 0 rgba(14,31,51,0.05); + --ring-focus: 0 0 0 3px rgba(30,58,95,0.25); + + /* ---------- Motion ---------- */ + --ease-standard: cubic-bezier(0.2, 0.7, 0.2, 1); + --ease-out: cubic-bezier(0.16, 1, 0.3, 1); + --ease-in: cubic-bezier(0.7, 0, 0.84, 0); + --dur-fast: 120ms; + --dur-base: 200ms; + --dur-slow: 360ms; +} + +/* ============================================================ + Paper texture — subtle grain on cream surfaces + ============================================================ */ +.paper-texture { + background-color: var(--bg-page); + background-image: + radial-gradient(rgba(14,31,51,0.025) 1px, transparent 1px), + radial-gradient(rgba(138,111,61,0.022) 1px, transparent 1px); + background-size: 3px 3px, 7px 7px; + background-position: 0 0, 1px 1px; +} +.paper-texture-strong { + background-color: var(--bg-page); + background-image: + radial-gradient(rgba(14,31,51,0.04) 1px, transparent 1.4px), + radial-gradient(rgba(138,111,61,0.035) 1px, transparent 1.2px); + background-size: 3px 3px, 7px 7px; +} + +/* ============================================================ + Element defaults — drop these into a body class .keysat + ============================================================ */ +.keysat { + font-family: var(--font-body); + font-size: var(--fs-body); + line-height: var(--lh-body); + color: var(--fg-1); + background: var(--bg-page); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-feature-settings: 'ss01', 'cv11'; +} + +.keysat h1, .keysat .h1 { + font-family: var(--font-display); + font-size: var(--fs-h1); + font-weight: 500; + line-height: var(--lh-heading); + letter-spacing: var(--tracking-tight); + color: var(--fg-1); + margin: 0; +} +.keysat h2, .keysat .h2 { + font-family: var(--font-display); + font-size: var(--fs-h2); + font-weight: 500; + line-height: var(--lh-heading); + letter-spacing: var(--tracking-tight); + color: var(--fg-1); + margin: 0; +} +.keysat h3, .keysat .h3 { + font-family: var(--font-display); + font-size: var(--fs-h3); + font-weight: 600; + line-height: var(--lh-tight); + letter-spacing: var(--tracking-tight); + margin: 0; +} +.keysat h4, .keysat .h4 { + font-family: var(--font-display); + font-size: var(--fs-h4); + font-weight: 600; + line-height: var(--lh-tight); + margin: 0; +} +.keysat h5, .keysat .h5 { + font-family: var(--font-body); + font-size: var(--fs-h5); + font-weight: 600; + line-height: var(--lh-tight); + margin: 0; +} +.keysat .display-xl { + font-family: var(--font-display); + font-size: var(--fs-display-xl); + font-weight: 500; + line-height: var(--lh-display); + letter-spacing: -0.022em; +} +.keysat .display { + font-family: var(--font-display); + font-size: var(--fs-display); + font-weight: 500; + line-height: var(--lh-display); + letter-spacing: -0.022em; +} +.keysat .wordmark { + font-family: var(--font-display); + font-weight: 500; + letter-spacing: 0.32em; + text-transform: uppercase; + color: var(--navy-800); +} +.keysat .eyebrow { + font-family: var(--font-body); + font-size: 11.5px; + font-weight: 600; + letter-spacing: var(--tracking-eyebrow); + text-transform: uppercase; + color: var(--gold-700); +} +.keysat p { margin: 0 0 1em 0; color: var(--fg-2); } +.keysat .lead { + font-size: var(--fs-body-lg); + line-height: 1.5; + color: var(--fg-2); +} +.keysat .meta { + font-size: var(--fs-meta); + color: var(--fg-3); + letter-spacing: 0.02em; +} +.keysat code, .keysat .mono { + font-family: var(--font-mono); + font-size: var(--fs-mono); + font-feature-settings: 'ss02'; +} +.keysat a { + color: var(--accent); + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 2px; +} +.keysat a:hover { color: var(--accent-hover); } diff --git a/design/tokens.tokens.json b/design/tokens.tokens.json new file mode 100644 index 0000000..903d9ab --- /dev/null +++ b/design/tokens.tokens.json @@ -0,0 +1,171 @@ +{ + "$description": "Keysat design tokens — W3C DTCG-shaped, distilled from design/_imports/2026-06-16-claude-design-system/colors_and_type.css (as-built values). Group-level $type is set where it maps cleanly to a DTCG primitive; a few groups (fontSize, letterSpacing, shadow) carry as-built CSS expressions (clamp(), em, multi-layer shadows) as strings and are intentionally left untyped pending a Style Dictionary build. See design/DESIGN.md for intent and rules.", + + "color": { + "$type": "color", + "navy": { + "950": { "$value": "#0E1F33" }, + "900": { "$value": "#142A47" }, + "800": { "$value": "#1E3A5F", "$description": "core brand navy — wordmark, primary buttons, dominant ink" }, + "700": { "$value": "#2A4A75" }, + "600": { "$value": "#3A5C8A" }, + "500": { "$value": "#5074A1" }, + "400": { "$value": "#7892B8" }, + "300": { "$value": "#A6B7CF" }, + "200": { "$value": "#CBD5E2" }, + "100": { "$value": "#E4EAF1" }, + "50": { "$value": "#F2F5F9" } + }, + "cream": { + "50": { "$value": "#FBF9F2", "$description": "elevated paper / card surface" }, + "100": { "$value": "#F5F1E8", "$description": "core cream — default page background" }, + "200": { "$value": "#EDE7D7" }, + "300": { "$value": "#E1D8C0" }, + "400": { "$value": "#C9BC9A" } + }, + "gold": { + "700": { "$value": "#8A6F3D", "$description": "eyebrow labels / dark gold accent" }, + "600": { "$value": "#A88652" }, + "500": { "$value": "#BFA068", "$description": "core gold accent — sparing use only, never a primary button fill" }, + "400": { "$value": "#D4B985" }, + "300": { "$value": "#E5CFA5" }, + "200": { "$value": "#F0E2C5" } + }, + "ink": { + "900": { "$value": "#0E1F33", "$description": "primary text" }, + "700": { "$value": "#2C3E54", "$description": "secondary text" }, + "500": { "$value": "#5A6B7F", "$description": "tertiary / meta" }, + "400": { "$value": "#7E8C9D", "$description": "disabled / hint" }, + "300": { "$value": "#A4AEBB" } + }, + "semantic": { + "success": { "$value": "#2D7A5F" }, + "success-bg": { "$value": "#E3F0EA" }, + "warning": { "$value": "#B8861F" }, + "warning-bg": { "$value": "#F7EFD7" }, + "danger": { "$value": "#B23A3A" }, + "danger-bg": { "$value": "#F4E0E0" }, + "info": { "$value": "{color.navy.700}" }, + "info-bg": { "$value": "{color.navy.100}" } + }, + "surface": { + "page": { "$value": "{color.cream.100}", "$description": "default page bg (apply with paper-texture grain)" }, + "paper": { "$value": "{color.cream.50}" }, + "elevated":{ "$value": "#FFFFFF", "$description": "forms, tables, code blocks — reserved white" }, + "inverse": { "$value": "{color.navy.900}" }, + "tint": { "$value": "{color.cream.200}" } + }, + "fg": { + "primary": { "$value": "{color.ink.900}" }, + "secondary": { "$value": "{color.ink.700}" }, + "tertiary": { "$value": "{color.ink.500}" }, + "hint": { "$value": "{color.ink.400}" }, + "on-navy": { "$value": "{color.cream.50}" }, + "on-gold": { "$value": "{color.navy.900}" } + }, + "accent": { + "default": { "$value": "{color.navy.800}" }, + "hover": { "$value": "{color.navy.900}" }, + "press": { "$value": "{color.navy.950}" }, + "soft": { "$value": "{color.navy.100}" }, + "gold": { "$value": "{color.gold.500}" } + }, + "border": { + "1": { "$value": "rgba(14, 31, 51, 0.12)", "$description": "hairline on cream" }, + "2": { "$value": "rgba(14, 31, 51, 0.20)", "$description": "card border" }, + "3": { "$value": "rgba(14, 31, 51, 0.35)", "$description": "focus / strong" }, + "on-navy": { "$value": "rgba(245, 241, 232, 0.18)" } + } + }, + + "font": { + "$type": "fontFamily", + "display": { "$value": ["Manrope", "Helvetica Neue", "Arial", "sans-serif"], "$description": "canonical display face (README's 'Archivo' was a stale placeholder)" }, + "body": { "$value": ["Inter", "Helvetica Neue", "Arial", "sans-serif"] }, + "mono": { "$value": ["JetBrains Mono", "ui-monospace", "SF Mono", "Menlo", "monospace"] } + }, + + "fontSize": { + "$description": "as-built type scale; display sizes use CSS clamp() and are kept as strings", + "display-xl": { "$value": "clamp(56px, 6vw, 88px)" }, + "display": { "$value": "clamp(40px, 4.5vw, 64px)" }, + "h1": { "$value": "44px" }, + "h2": { "$value": "32px" }, + "h3": { "$value": "24px" }, + "h4": { "$value": "20px" }, + "h5": { "$value": "17px" }, + "body-lg": { "$value": "18px" }, + "body": { "$value": "15px" }, + "body-sm": { "$value": "13.5px" }, + "meta": { "$value": "12px" }, + "mono": { "$value": "13px" } + }, + + "lineHeight": { + "$type": "number", + "display": { "$value": 1.02 }, + "heading": { "$value": 1.15 }, + "body": { "$value": 1.55 }, + "tight": { "$value": 1.25 } + }, + + "letterSpacing": { + "$description": "em values kept as strings", + "tight": { "$value": "-0.02em" }, + "normal": { "$value": "0" }, + "wide": { "$value": "0.04em" }, + "eyebrow": { "$value": "0.18em" } + }, + + "space": { + "$type": "dimension", + "1": { "$value": "4px" }, + "2": { "$value": "8px" }, + "3": { "$value": "12px" }, + "4": { "$value": "16px" }, + "5": { "$value": "20px" }, + "6": { "$value": "24px" }, + "7": { "$value": "32px" }, + "8": { "$value": "40px" }, + "9": { "$value": "56px" }, + "10": { "$value": "72px" }, + "11": { "$value": "96px" }, + "12": { "$value": "128px" } + }, + + "radius": { + "$type": "dimension", + "xs": { "$value": "3px" }, + "sm": { "$value": "5px" }, + "md": { "$value": "8px", "$description": "buttons" }, + "lg": { "$value": "12px", "$description": "cards" }, + "xl": { "$value": "18px", "$description": "max surface rounding — never exceed" }, + "2xl": { "$value": "24px", "$description": "reserved; avoid in product UI" }, + "pill": { "$value": "999px", "$description": "tags/badges only" } + }, + + "shadow": { + "$description": "paper-shadow system — multi-layer CSS strings, not glassy", + "xs": { "$value": "0 1px 1px rgba(14,31,51,0.04)" }, + "sm": { "$value": "0 1px 2px rgba(14,31,51,0.06), 0 1px 1px rgba(14,31,51,0.03)" }, + "md": { "$value": "0 2px 4px rgba(14,31,51,0.06), 0 4px 12px rgba(14,31,51,0.06)" }, + "lg": { "$value": "0 4px 8px rgba(14,31,51,0.07), 0 12px 32px rgba(14,31,51,0.10)" }, + "xl": { "$value": "0 8px 16px rgba(14,31,51,0.10), 0 24px 64px rgba(14,31,51,0.14)" }, + "inset": { "$value": "inset 0 1px 0 rgba(255,255,255,0.6), inset 0 -1px 0 rgba(14,31,51,0.05)" }, + "ring-focus": { "$value": "0 0 0 3px rgba(30,58,95,0.25)" } + }, + + "duration": { + "$type": "duration", + "fast": { "$value": "120ms", "$description": "hover transitions" }, + "base": { "$value": "200ms", "$description": "default" }, + "slow": { "$value": "360ms" } + }, + + "easing": { + "$type": "cubicBezier", + "standard": { "$value": [0.2, 0.7, 0.2, 1] }, + "out": { "$value": [0.16, 1, 0.3, 1] }, + "in": { "$value": [0.7, 0, 0.84, 0] } + } +}