Files
bitlogin/packages/demo/public/assets/site.css
T
Claude 5ee63ae6b0 Implement BitLogin as a modular protocol library, embeddable widget, and demo site
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
2026-07-21 03:44:10 +00:00

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;
}