mirror of
https://github.com/PR0M3TH3AN/bitlogin.git
synced 2026-10-27 08:31:21 +00:00
Builds out the v0.3 spec as an npm workspace monorepo any static site can consume for login and Nostr signing: - packages/core: framework-free protocol implementation — Argon2id/HKDF/ ScalarExpand/AES-256-GCM/JCS crypto primitives, NIP-01 event handling and a quorum-aware relay pool, credential/recovery capsule construction and validation, and the full account lifecycle (registration, any-device login with rollback/relay-disagreement detection, phrase recovery with recovery-capsule refresh, password rotation with mandatory tombstone + NIP-09 deletion, replica repair, recovery export, NIP-19 encoding, a NIP-44 v2 implementation, and a NIP-07-shaped signer). 49 tests cover the spec's Phase 0 byte-level vectors plus full create/login/recover/rotate end-to-end scenarios against an in-memory mock relay. - packages/widget: a <bitlogin-auth> custom element with a dedicated crypto Web Worker (private keys never touch the main thread) and a window.nostr NIP-07-compatible provider, so existing Nostr web apps work against it with zero code changes. Built with Vite into two relocatable static files. - packages/demo: a plain static site (no build step of its own) consuming the widget — a branding/landing page, an integration guide, and an account-manager page covering create/login/recover, password rotation, and identity export. All flows were verified twice: protocol-level tests against a mock relay, and the actual built widget driven end-to-end in real Chromium (registration, phrase confirmation, event signing, clean-device login, window.nostr, and phrase recovery all reproduce the identical everyday pubkey). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01GWJbXXhvTx9wo59jSz57J6
220 lines
5.3 KiB
CSS
220 lines
5.3 KiB
CSS
:root {
|
|
--bg: #0b0b12;
|
|
--bg-elevated: #141420;
|
|
--fg: #f2f1f7;
|
|
--muted: #9995ab;
|
|
--border: #26243a;
|
|
--accent: #8b5cf6;
|
|
--accent2: #ec4899;
|
|
--code-bg: #100f19;
|
|
color-scheme: dark;
|
|
}
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
--bg: #fbfaff;
|
|
--bg-elevated: #ffffff;
|
|
--fg: #17151f;
|
|
--muted: #6b6478;
|
|
--border: #e7e4f2;
|
|
--code-bg: #14121f;
|
|
}
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
html, body { margin: 0; padding: 0; }
|
|
body {
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
line-height: 1.6;
|
|
}
|
|
a { color: var(--accent); text-decoration: none; }
|
|
a:hover { text-decoration: underline; }
|
|
|
|
.nav {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
max-width: 1080px;
|
|
margin: 0 auto;
|
|
padding: 20px 24px;
|
|
}
|
|
.nav .brand {
|
|
font-weight: 700;
|
|
font-size: 18px;
|
|
letter-spacing: -0.02em;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
.nav .brand .dot {
|
|
width: 10px; height: 10px; border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--accent), var(--accent2));
|
|
display: inline-block;
|
|
}
|
|
.nav .links { display: flex; gap: 22px; font-size: 14px; }
|
|
.nav .links a { color: var(--muted); }
|
|
.nav .links a.active, .nav .links a:hover { color: var(--fg); }
|
|
|
|
.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
|
|
.narrow { max-width: 760px; }
|
|
|
|
.hero {
|
|
padding: 72px 24px 40px;
|
|
text-align: center;
|
|
}
|
|
.hero h1 {
|
|
font-size: clamp(34px, 6vw, 56px);
|
|
font-weight: 800;
|
|
letter-spacing: -0.03em;
|
|
margin: 0 0 18px;
|
|
background: linear-gradient(135deg, var(--fg) 30%, var(--accent) 100%);
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
}
|
|
.hero p.lead {
|
|
color: var(--muted);
|
|
font-size: 18px;
|
|
max-width: 620px;
|
|
margin: 0 auto 30px;
|
|
}
|
|
.cta-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
|
|
.btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 12px 22px;
|
|
border-radius: 10px;
|
|
font-weight: 600;
|
|
font-size: 14.5px;
|
|
border: 1px solid var(--border);
|
|
}
|
|
.btn.primary {
|
|
background: linear-gradient(135deg, var(--accent), var(--accent2));
|
|
color: white;
|
|
border: none;
|
|
}
|
|
.btn.primary:hover { opacity: 0.92; text-decoration: none; }
|
|
.btn.secondary { color: var(--fg); }
|
|
.btn.secondary:hover { background: var(--bg-elevated); text-decoration: none; }
|
|
|
|
.diagram {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
margin: 48px 0;
|
|
font-size: 13.5px;
|
|
}
|
|
.diagram .step {
|
|
background: var(--bg-elevated);
|
|
border: 1px solid var(--border);
|
|
border-radius: 12px;
|
|
padding: 14px 16px;
|
|
min-width: 140px;
|
|
text-align: center;
|
|
}
|
|
.diagram .step .k { color: var(--muted); font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 4px; }
|
|
.diagram .arrow { color: var(--muted); font-size: 18px; }
|
|
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
|
|
gap: 16px;
|
|
margin: 40px 0;
|
|
}
|
|
.feature {
|
|
background: var(--bg-elevated);
|
|
border: 1px solid var(--border);
|
|
border-radius: 14px;
|
|
padding: 20px;
|
|
}
|
|
.feature h3 { margin: 0 0 8px; font-size: 15.5px; }
|
|
.feature p { margin: 0; color: var(--muted); font-size: 13.5px; }
|
|
|
|
section { padding: 20px 0 40px; }
|
|
h2 { font-size: 26px; letter-spacing: -0.02em; margin: 0 0 6px; }
|
|
p.section-sub { color: var(--muted); margin: 0 0 28px; }
|
|
|
|
pre {
|
|
background: var(--code-bg);
|
|
color: #e8e6f5;
|
|
border: 1px solid var(--border);
|
|
border-radius: 12px;
|
|
padding: 18px;
|
|
overflow-x: auto;
|
|
font-size: 13px;
|
|
line-height: 1.55;
|
|
}
|
|
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
:not(pre) > code {
|
|
background: var(--bg-elevated);
|
|
border: 1px solid var(--border);
|
|
border-radius: 5px;
|
|
padding: 1px 5px;
|
|
font-size: 0.92em;
|
|
}
|
|
|
|
.step-list { counter-reset: step; list-style: none; padding: 0; margin: 0; }
|
|
.step-list > li {
|
|
counter-increment: step;
|
|
position: relative;
|
|
padding: 0 0 28px 44px;
|
|
border-left: 2px solid var(--border);
|
|
margin-left: 15px;
|
|
}
|
|
.step-list > li:last-child { border-left-color: transparent; padding-bottom: 0; }
|
|
.step-list > li::before {
|
|
content: counter(step);
|
|
position: absolute;
|
|
left: -15px;
|
|
top: 0;
|
|
width: 28px; height: 28px;
|
|
border-radius: 50%;
|
|
background: linear-gradient(135deg, var(--accent), var(--accent2));
|
|
color: white;
|
|
font-weight: 700;
|
|
font-size: 13px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.step-list h3 { margin: 2px 0 8px; font-size: 16px; }
|
|
|
|
.callout {
|
|
border: 1px solid var(--border);
|
|
background: var(--bg-elevated);
|
|
border-radius: 12px;
|
|
padding: 14px 16px;
|
|
font-size: 13.5px;
|
|
color: var(--muted);
|
|
margin: 18px 0;
|
|
}
|
|
.callout strong { color: var(--fg); }
|
|
|
|
.app-layout {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: 48px 24px 80px;
|
|
}
|
|
.app-layout .side {
|
|
max-width: 340px;
|
|
margin-right: 40px;
|
|
}
|
|
.app-layout .side h1 { font-size: 26px; margin: 0 0 10px; }
|
|
.app-layout .side p { color: var(--muted); font-size: 14px; }
|
|
@media (max-width: 820px) {
|
|
.app-layout { flex-direction: column; align-items: center; }
|
|
.app-layout .side { margin-right: 0; margin-bottom: 24px; text-align: center; }
|
|
}
|
|
|
|
footer {
|
|
border-top: 1px solid var(--border);
|
|
padding: 28px 24px;
|
|
text-align: center;
|
|
color: var(--muted);
|
|
font-size: 13px;
|
|
}
|