- settings: add Theme::Impeccable / ImpeccableDark (serde rename impeccable-dark) - types: extend Theme union - styles: add :root[data-theme=impeccable] (oklch lacquer/kinpaku) and impeccable-dark (lacquer-deep), Alumni Sans display, editorial refinements - SettingsScreen: add Impeccable options with live swatch preview - ProfilesScreen: wire ProfileEditModal (Paper Lift) with segmented tabs, keep legacy modals for compat - DESIGN.md/PRODUCT.md + .impeccable/design.json from impeccable document
380 lines
No EOL
15 KiB
JSON
380 lines
No EOL
15 KiB
JSON
{
|
||
"schemaVersion": 2,
|
||
"generatedAt": "2026-08-27T18:00:17.873Z",
|
||
"title": "Design System: Nostr Keynctr",
|
||
"extensions": {
|
||
"colorMeta": {
|
||
"warm-ivory": {
|
||
"role": "neutral",
|
||
"displayName": "Warm Ivory",
|
||
"canonical": "#f6f4f0",
|
||
"tonalRamp": [
|
||
"#1e1b15",
|
||
"#3d3830",
|
||
"#5c564e",
|
||
"#7c756d",
|
||
"#9c958d",
|
||
"#bdb9b3",
|
||
"#deddda",
|
||
"#f6f4f0"
|
||
]
|
||
},
|
||
"paper": {
|
||
"role": "neutral",
|
||
"displayName": "Paper",
|
||
"canonical": "#ffffff",
|
||
"tonalRamp": [
|
||
"#1f1b15",
|
||
"#3e3a34",
|
||
"#5d5953",
|
||
"#7d7872",
|
||
"#9c9791",
|
||
"#bcb6b0",
|
||
"#deddda",
|
||
"#ffffff"
|
||
]
|
||
},
|
||
"soft-stone": {
|
||
"role": "neutral",
|
||
"displayName": "Soft Stone",
|
||
"canonical": "#f1ede7",
|
||
"tonalRamp": [
|
||
"#1d1b18",
|
||
"#3c3936",
|
||
"#5b5854",
|
||
"#7a7772",
|
||
"#999690",
|
||
"#b8b5ae",
|
||
"#d7d4cc",
|
||
"#f1ede7"
|
||
]
|
||
},
|
||
"ink": {
|
||
"role": "neutral",
|
||
"displayName": "Graphite Ink",
|
||
"canonical": "#201b15",
|
||
"tonalRamp": [
|
||
"#201b15",
|
||
"#4d4741",
|
||
"#7a756d",
|
||
"#a7a39e",
|
||
"#d4d1ce",
|
||
"#eceae8",
|
||
"#f5f4f3",
|
||
"#faf9f8"
|
||
]
|
||
},
|
||
"ink-muted": {
|
||
"role": "neutral",
|
||
"displayName": "Ink Muted",
|
||
"canonical": "#6d655a",
|
||
"tonalRamp": [
|
||
"#2a2722",
|
||
"#403d38",
|
||
"#56544f",
|
||
"#6d655a",
|
||
"#8a857e",
|
||
"#a7a5a1",
|
||
"#c4c2be",
|
||
"#e1dfdc"
|
||
]
|
||
},
|
||
"line": {
|
||
"role": "neutral",
|
||
"displayName": "Line",
|
||
"canonical": "#e6e0d6",
|
||
"tonalRamp": [
|
||
"#2c2a27",
|
||
"#4a4845",
|
||
"#686663",
|
||
"#868481",
|
||
"#a4a29f",
|
||
"#c2c0bd",
|
||
"#e0dedb",
|
||
"#e6e0d6"
|
||
]
|
||
},
|
||
"antique-brass": {
|
||
"role": "primary",
|
||
"displayName": "Antique Brass",
|
||
"canonical": "#6d5ae6",
|
||
"tonalRamp": [
|
||
"#221b4a",
|
||
"#3a2d7a",
|
||
"#523faa",
|
||
"#6d5ae6",
|
||
"#8b7cff",
|
||
"#a99dff",
|
||
"#c7bdff",
|
||
"#efecfd"
|
||
]
|
||
},
|
||
"antique-brass-soft": {
|
||
"role": "primary",
|
||
"displayName": "Brass Wash",
|
||
"canonical": "#efecfd",
|
||
"tonalRamp": [
|
||
"#221b4a",
|
||
"#3a2d7a",
|
||
"#523faa",
|
||
"#6d5ae6",
|
||
"#8b7cff",
|
||
"#c7bdff",
|
||
"#efecfd",
|
||
"#f8f7ff"
|
||
]
|
||
},
|
||
"signal-coral": {
|
||
"role": "neutral",
|
||
"displayName": "Signal Coral",
|
||
"canonical": "#c0392b",
|
||
"tonalRamp": [
|
||
"#3a1512",
|
||
"#5a1f1b",
|
||
"#7a2a24",
|
||
"#9a352d",
|
||
"#c0392b",
|
||
"#d66a60",
|
||
"#e99a96",
|
||
"#fdecec"
|
||
]
|
||
},
|
||
"muted-sage": {
|
||
"role": "neutral",
|
||
"displayName": "Muted Sage",
|
||
"canonical": "#22713c",
|
||
"tonalRamp": [
|
||
"#0f2a18",
|
||
"#143d22",
|
||
"#1a502c",
|
||
"#22713c",
|
||
"#4a8a5f",
|
||
"#73a382",
|
||
"#9cbca5",
|
||
"#e7f5ec"
|
||
]
|
||
},
|
||
"antique-gold": {
|
||
"role": "neutral",
|
||
"displayName": "Antique Gold",
|
||
"canonical": "#9a6b13",
|
||
"tonalRamp": [
|
||
"#2e2110",
|
||
"#4a3418",
|
||
"#664720",
|
||
"#825a28",
|
||
"#9a6b13",
|
||
"#b88a3a",
|
||
"#d6aa62",
|
||
"#fcf3e0"
|
||
]
|
||
},
|
||
"clear-ink": {
|
||
"role": "neutral",
|
||
"displayName": "Clear Ink",
|
||
"canonical": "#2868a4",
|
||
"tonalRamp": [
|
||
"#0f2538",
|
||
"#163a58",
|
||
"#1d4f78",
|
||
"#2868a4",
|
||
"#4d82b4",
|
||
"#739dc4",
|
||
"#99b8d4",
|
||
"#e9f2fb"
|
||
]
|
||
}
|
||
},
|
||
"typographyMeta": {
|
||
"display": {
|
||
"displayName": "Display",
|
||
"purpose": "Page titles (h1) only — 24px, weight 650."
|
||
},
|
||
"headline": {
|
||
"displayName": "Headline",
|
||
"purpose": "Card and modal heads (h2) — 16px, weight 650."
|
||
},
|
||
"body": {
|
||
"displayName": "Body",
|
||
"purpose": "Reading text — 15px / 1.5, max 65–75ch."
|
||
},
|
||
"label": {
|
||
"displayName": "Label",
|
||
"purpose": "Field labels and hints — 13px / 600."
|
||
},
|
||
"mono": {
|
||
"displayName": "Mono",
|
||
"purpose": "Code and npub — SFMono 13.8px."
|
||
}
|
||
},
|
||
"shadows": [
|
||
{
|
||
"name": "paper-lift",
|
||
"value": "0 1px 2px rgba(30,25,18,0.05), 0 8px 24px rgba(30,25,18,0.06)",
|
||
"purpose": "Default card lift on Warm Ivory."
|
||
},
|
||
{
|
||
"name": "modal-lift",
|
||
"value": "0 12px 40px rgba(20,15,10,0.22)",
|
||
"purpose": "Modal over app."
|
||
},
|
||
{
|
||
"name": "neon-glow",
|
||
"value": "0 0 32px rgba(255,20,147,0.12)",
|
||
"purpose": "Gated neon modal glow only on dark."
|
||
}
|
||
],
|
||
"motion": [
|
||
{
|
||
"name": "ease-standard",
|
||
"value": "0.12s ease",
|
||
"purpose": "Button, nav, border-color transitions."
|
||
},
|
||
{
|
||
"name": "ease-glass",
|
||
"value": "blur 18px saturate(160%)",
|
||
"purpose": "Aurora glass panels."
|
||
}
|
||
],
|
||
"breakpoints": [
|
||
{
|
||
"name": "sidebar",
|
||
"value": "920px"
|
||
},
|
||
{
|
||
"name": "card-grid",
|
||
"value": "280px"
|
||
}
|
||
]
|
||
},
|
||
"components": [
|
||
{
|
||
"name": "Primary Button",
|
||
"kind": "button",
|
||
"refersTo": "button-primary",
|
||
"description": "Main action — Antique Brass on Paper.",
|
||
"html": "<button class=\"ds-btn-primary\">Publish</button>",
|
||
"css": ".ds-btn-primary{background:var(--primary);color:var(--on-primary);border:1px solid transparent;border-radius:9px;padding:10px 18px;font-weight:600;transition:background 0.12s ease} .ds-btn-primary:hover{background:var(--primary-hover)} .ds-btn-primary:focus-visible{outline:2px solid var(--focus);outline-offset:2px}"
|
||
},
|
||
{
|
||
"name": "Secondary Button",
|
||
"kind": "button",
|
||
"refersTo": "button-secondary",
|
||
"description": "Paper button with strong line border.",
|
||
"html": "<button class=\"ds-btn-secondary\">Select</button>",
|
||
"css": ".ds-btn-secondary{background:var(--surface);color:var(--text);border:1px solid var(--border-strong);border-radius:9px;padding:10px 18px;font-weight:600} .ds-btn-secondary:hover{background:var(--surface-hover)}"
|
||
},
|
||
{
|
||
"name": "Ghost Button",
|
||
"kind": "button",
|
||
"refersTo": "button-ghost",
|
||
"description": "Transparent for tertiary actions.",
|
||
"html": "<button class=\"ds-btn-ghost\">Edit name</button>",
|
||
"css": ".ds-btn-ghost{background:transparent;color:var(--text-muted);border:1px solid transparent;border-radius:9px;padding:7px 12px;font-weight:600} .ds-btn-ghost:hover{background:var(--surface-2);color:var(--text)}"
|
||
},
|
||
{
|
||
"name": "Danger Button",
|
||
"kind": "button",
|
||
"refersTo": "button-danger",
|
||
"description": "Signal Coral wash for destructive actions.",
|
||
"html": "<button class=\"ds-btn-danger\">Delete</button>",
|
||
"css": ".ds-btn-danger{background:var(--danger-soft);color:var(--danger);border:1px solid transparent;border-radius:9px;padding:7px 12px;font-weight:600} .ds-btn-danger:hover{background:var(--danger);color:#fff}"
|
||
},
|
||
{
|
||
"name": "Card",
|
||
"kind": "card",
|
||
"refersTo": "card",
|
||
"description": "Paper surface with soft lift.",
|
||
"html": "<div class=\"ds-card\"><div class=\"ds-card-head\">Active profile</div><div class=\"ds-card-body\">Profile content</div></div>",
|
||
"css": ".ds-card{background:var(--surface);border:1px solid var(--border);border-radius:14px;box-shadow:0 1px 2px rgba(30,25,18,0.05),0 8px 24px rgba(30,25,18,0.06);overflow:hidden} .ds-card-head{padding:16px 20px;border-bottom:1px solid var(--border);font-weight:650} .ds-card-body{padding:20px}"
|
||
},
|
||
{
|
||
"name": "Input",
|
||
"kind": "input",
|
||
"refersTo": "input",
|
||
"description": "Paper field with strong line border.",
|
||
"html": "<label class=\"ds-field\">Label<input class=\"ds-input\" placeholder=\"name@domain.com\" /></label>",
|
||
"css": ".ds-input{font:inherit;color:var(--text);background:var(--surface);border:1px solid var(--border-strong);border-radius:9px;padding:10px 12px;width:100%} .ds-input:focus{outline:none;border-color:var(--focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--focus) 22%, transparent)}"
|
||
},
|
||
{
|
||
"name": "Navigation Item",
|
||
"kind": "nav",
|
||
"refersTo": "nav-item",
|
||
"description": "Sidebar nav with muted → brass active.",
|
||
"html": "<button class=\"ds-nav is-active\">Home</button>",
|
||
"css": ".ds-nav{display:flex;gap:12px;padding:11px 12px;border-radius:9px;border:none;background:transparent;color:var(--text-muted);font-weight:550} .ds-nav:hover{background:var(--surface-2);color:var(--text)} .ds-nav.is-active{background:var(--primary-soft);color:var(--primary)}"
|
||
},
|
||
{
|
||
"name": "Undo Bar",
|
||
"kind": "custom",
|
||
"refersTo": "undo-bar",
|
||
"description": "Themed dismissal bar after delete — 5s, primary-soft.",
|
||
"html": "<div class=\"ds-undo\"><span>Profile “Alice” deleted.</span><span>—</span><button class=\"ds-undo-link\">Undo and restore profile</button></div>",
|
||
"css": ".ds-undo{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:12px 0;padding:10px 14px;background:var(--primary-soft);border:1px solid var(--border);border-radius:8px} .ds-undo-link{background:none;border:none;padding:0;color:var(--primary);font-weight:600;cursor:pointer;text-decoration:underline;text-underline-offset:2px}"
|
||
},
|
||
{
|
||
"name": "Badge",
|
||
"kind": "chip",
|
||
"refersTo": "badge",
|
||
"description": "Pill tag for state.",
|
||
"html": "<span class=\"ds-badge success\">Active</span>",
|
||
"css": ".ds-badge{display:inline-flex;gap:5px;padding:3px 10px;border-radius:999px;font-size:12px;font-weight:650;white-space:nowrap} .ds-badge.success{background:var(--success-soft);color:var(--success)}"
|
||
},
|
||
{
|
||
"name": "Profile Edit Modal",
|
||
"kind": "custom",
|
||
"refersTo": "modal-profile-edit",
|
||
"description": "Paper modal for Rename / Picture / NIP-05 — Paper Lift, vault separation.",
|
||
"html": "<div class=\"ds-backdrop\"><div class=\"ds-modal\"><div class=\"ds-modal-head\"><h3>Edit profile — Alice</h3><button class=\"ds-icon\">×</button></div><div class=\"ds-modal-body\"><div class=\"ds-avatar-lg\">A</div><p class=\"ds-muted\">Public npub is visible to relays; private key never leaves Rust.</p><label class=\"ds-field\"><span>Profile name</span><input class=\"ds-input\" value=\"Alice\" /></label><label class=\"ds-field\"><span>Picture URL</span><input class=\"ds-input\" placeholder=\"https://…/avatar.png\" /></label><label class=\"ds-field\"><span>NIP-05</span><input class=\"ds-input\" placeholder=\"alice@example.com\" /></label><div class=\"ds-modal-actions\"><button class=\"ds-btn-danger\">Remove profile</button><span style=\"flex:1\"></span><button class=\"ds-btn-ghost\">Cancel</button><button class=\"ds-btn-primary\">Save & publish</button></div></div></div></div>",
|
||
"css": ".ds-backdrop{position:fixed;inset:0;background:rgba(20,16,12,0.45);display:grid;place-items:center;padding:24px} .ds-modal{background:var(--surface);border:1px solid var(--border);border-radius:16px;box-shadow:0 12px 40px rgba(20,15,10,0.22);width:100%;max-width:520px;max-height:88vh;overflow:auto} .ds-modal-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:18px 22px;border-bottom:1px solid var(--border);font-weight:650} .ds-modal-body{padding:20px 22px;display:flex;flex-direction:column;gap:16px} .ds-avatar-lg{width:52px;height:52px;border-radius:50%;display:grid;place-items:center;background:var(--primary-soft);color:var(--primary);font-weight:700;font-size:21px} .ds-muted{color:var(--text-muted);font-size:13px;margin:0} .ds-field{display:flex;flex-direction:column;gap:6px;font-size:13px;font-weight:600;color:var(--text)} .ds-modal-actions{display:flex;justify-content:flex-end;gap:10px;align-items:center;margin-top:4px} .ds-icon{width:34px;height:34px;border-radius:999px;border:1px solid var(--border);background:var(--surface)} [data-theme=\"glass\"] .ds-modal{backdrop-filter:blur(18px) saturate(160%);-webkit-backdrop-filter:blur(18px) saturate(160%)} [data-theme=\"neon\"] .ds-modal{box-shadow:0 12px 40px rgba(0,0,0,0.85),0 0 32px rgba(255,20,147,0.12)}"
|
||
}
|
||
],
|
||
"narrative": {
|
||
"northStar": "Vault & Atelier",
|
||
"overview": "Nostr Keynctr is an atelier, not a dashboard — a warm, quiet workshop where identity work is done with care. The space feels like heavy paper and soft stone, with ink that is near-black, not pure black. Instruments are laid out plainly; nothing shouts for attention. Trust is built through precision: consistent edges, settled type, and state that is always legible.",
|
||
"keyCharacteristics": [
|
||
"Warm and human, precise and calm",
|
||
"Paper and stone material language — tonal layering over heavy shadows",
|
||
"Semantic tokens only — every color has a job",
|
||
"Operate density — tasks complete faster because hierarchy is consistent",
|
||
"Vault logic made visible — locked/muted states are distinct at a glance"
|
||
],
|
||
"rules": [
|
||
{
|
||
"name": "The One Accent Rule",
|
||
"body": "Antique Brass is the only saturated accent in the restrained palette. Its rarity is the point — use it for primary actions and active state only.",
|
||
"section": "colors"
|
||
},
|
||
{
|
||
"name": "The Vault Separation Rule",
|
||
"body": "Secret-dependent UI never shares color with public data: private operations are flagged via muted-sage/signal-coral and explicit Approve/Reject.",
|
||
"section": "colors"
|
||
},
|
||
{
|
||
"name": "The Weight Restraint Rule",
|
||
"body": "Only headings are 650. Do not add semibold to body or emphasize muted text with weight.",
|
||
"section": "typography"
|
||
},
|
||
{
|
||
"name": "The Flat-By-Default Rule",
|
||
"body": "Surfaces are flat at rest. Shadows appear only as a response to layer (card on canvas, modal over app).",
|
||
"section": "elevation"
|
||
}
|
||
],
|
||
"dos": [
|
||
"Do keep Warm Ivory as the only page canvas on light",
|
||
"Do use Muted Sage wash only for successful security confirmation",
|
||
"Do keep one primary per screen — Antique Brass is rare by design",
|
||
"Do use var(--focus) for every focus ring; keep the 2px + 2px offset invariant",
|
||
"Do preserve the side-by-side rate: cards on Paper with 1px Line borders before adding any shadow"
|
||
],
|
||
"donts": [
|
||
"Don't use Signal Coral outside error/destructive states",
|
||
"Don't introduce a new accent hue outside the four semantic washes",
|
||
"Don't bump heading weight beyond 650 or add bold to muted text",
|
||
"Don't apply neon glow outside data-theme='neon' modals",
|
||
"Don't invent a new radius — step on 9px/14px/16px/999px only",
|
||
"Don't replace the 5s auto-dismiss undo bar with a permanent modal"
|
||
]
|
||
}
|
||
} |