Redesign demo site around a "one login, every site" pitch

The old landing page led with generic Nostr-signer framing and a
templated violet/pink gradient look. Reframe the pitch around the
thing that's actually differentiated: one login name and password
that works on every BitLogin site, explicitly positioned against
NIP-07 extensions and NIP-46 bunkers, with Nostr terminology kept
light for the non-technical end users who'll actually be typing a
password rather than integrating a widget.

Visual redesign: warm parchment/brass accent alongside the existing
violet, Fraunces display serif paired with the existing system-ui
body font, and a new "one credential, many doors" hero illustration
with a staggered stamp-in animation (prefers-reduced-motion aware)
replacing the generic feature-grid-only layout. Applied consistently
across index.html, docs.html, and account.html.
This commit is contained in:
thePR0M3TH3AN committed 2026-07-21 16:17:37 -04:00
1 parent ce6ade73b4
commit 207f4cba10
5 files changed
+453 -111

No files matched your search

+15 -2
View File
@@ -7,12 +7,24 @@
<meta name="description" content="Create, sign in to, recover, and manage a BitLogin account — including password rotation and identity export." />
<link rel="icon" href="./assets/icon.svg" type="image/svg+xml" />
<link rel="manifest" href="./manifest.webmanifest" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,500;0,9..144,600;1,9..144,500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="./assets/site.css" />
</head>
<body>
<nav class="nav">
<a class="brand" href="./index.html"><span class="dot"></span>BitLogin</a>
<a class="brand" href="./index.html">
<span class="dot">
<svg viewBox="0 0 64 64" aria-hidden="true">
<circle cx="32" cy="32" r="30" fill="none" stroke="#d1a85a" stroke-width="4" />
<circle cx="32" cy="32" r="20" fill="#8368ff" />
<path d="M22 32.5l7 7 13-14.5" fill="none" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
BitLogin
</a>
<div class="links">
<a href="./index.html">Overview</a>
<a href="./docs.html">Integrate</a>
@@ -22,13 +34,14 @@
<div class="app-layout">
<div class="side">
<span class="eyebrow">Live demo</span>
<h1>Try a real account</h1>
<p>
This page embeds the exact <code>&lt;bitlogin-auth&gt;</code> element any static site would use — nothing
special is happening behind the scenes.
</p>
<p>
Create an account to see a generated passphrase and a 12-word recovery phrase, sign a test Nostr event,
Create an account to see a generated passphrase and a 12-word recovery phrase, sign a test event,
rotate your password (old capsule is tombstoned), and export a recovery file — or reload this page and
sign back in from a "clean" browser state.
</p>
+16 -6
View File
@@ -1,10 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#8b5cf6"/>
<stop offset="1" stop-color="#ec4899"/>
<linearGradient id="ink" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#17141f" />
<stop offset="1" stop-color="#0d0b12" />
</linearGradient>
<linearGradient id="seal" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#8368ff" />
<stop offset="1" stop-color="#6a4de8" />
</linearGradient>
<linearGradient id="brass" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#e6c481" />
<stop offset="1" stop-color="#b3924a" />
</linearGradient>
</defs>
<rect width="64" height="64" rx="16" fill="#0b0b12"/>
<circle cx="32" cy="32" r="16" fill="url(#g)"/>
<rect width="64" height="64" rx="15" fill="url(#ink)" />
<circle cx="32" cy="32" r="21" fill="none" stroke="url(#brass)" stroke-width="2.5" />
<circle cx="32" cy="32" r="14" fill="url(#seal)" />
<path d="M27 32.5l3.6 3.6L38 28.2" fill="none" stroke="#ffffff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" />
</svg>

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 969 B

+298 -72
View File
@@ -1,104 +1,315 @@
:root {
--bg: #0b0b12;
--bg-elevated: #141420;
--fg: #f2f1f7;
--muted: #9995ab;
--border: #26243a;
--accent: #8b5cf6;
--accent2: #ec4899;
--code-bg: #100f19;
--ink: #0d0b12;
--ink-soft: #17141f;
--ink-softer: #201c2b;
--paper: #f3ead9;
--paper-dim: #e8dcc2;
--seal: #8368ff;
--seal-deep: #6a4de8;
--brass: #d1a85a;
--brass-soft: #9c824f;
--fg: #f4f1ea;
--muted: #a49cb0;
--line: rgba(244, 241, 234, 0.11);
--line-strong: rgba(244, 241, 234, 0.2);
--code-bg: #100e17;
--shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
--font-display: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;
color-scheme: dark;
}
@media (prefers-color-scheme: light) {
:root {
--bg: #fbfaff;
--bg-elevated: #ffffff;
--fg: #17151f;
--muted: #6b6478;
--border: #e7e4f2;
--code-bg: #14121f;
--ink: #f7f2e7;
--ink-soft: #ffffff;
--ink-softer: #efe8d8;
--paper: #ffffff;
--paper-dim: #efe8d8;
--seal: #6a4de8;
--seal-deep: #5638c9;
--brass: #9c7a2e;
--brass-soft: #b3924a;
--fg: #211c2c;
--muted: #675f75;
--line: rgba(33, 28, 44, 0.12);
--line-strong: rgba(33, 28, 44, 0.22);
--code-bg: #211c2c;
color-scheme: light;
}
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
background: var(--bg);
background:
radial-gradient(1100px 620px at 82% -10%, color-mix(in srgb, var(--seal) 16%, transparent), transparent 60%),
radial-gradient(900px 500px at -10% 15%, color-mix(in srgb, var(--brass) 10%, transparent), transparent 55%),
var(--ink);
color: var(--fg);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
font-family: var(--font-body);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a { color: var(--seal); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible {
outline: 2px solid var(--brass);
outline-offset: 3px;
border-radius: 4px;
}
/* ---------- nav ---------- */
.nav {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1080px;
max-width: 1120px;
margin: 0 auto;
padding: 20px 24px;
padding: 22px 24px;
}
.nav .brand {
font-weight: 700;
font-size: 18px;
letter-spacing: -0.02em;
font-family: var(--font-display);
font-weight: 600;
font-size: 19px;
letter-spacing: -0.01em;
display: flex;
align-items: center;
gap: 8px;
gap: 10px;
color: var(--fg);
}
.nav .brand .dot {
width: 10px; height: 10px; border-radius: 50%;
background: linear-gradient(135deg, var(--accent), var(--accent2));
width: 20px;
height: 20px;
display: inline-block;
flex-shrink: 0;
}
.nav .links { display: flex; gap: 22px; font-size: 14px; }
.nav .brand .dot svg { width: 100%; height: 100%; display: block; }
.nav .links { display: flex; gap: 26px; font-size: 14px; }
.nav .links a { color: var(--muted); }
.nav .links a.active, .nav .links a:hover { color: var(--fg); }
.nav .links a.active, .nav .links a:hover { color: var(--fg); text-decoration: none; }
.nav .links a.active { position: relative; }
.nav .links a.active::after {
content: "";
position: absolute;
left: 0; right: 0; bottom: -8px;
height: 2px;
background: var(--brass);
border-radius: 2px;
}
.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
.container { max-width: 1120px; margin: 0 auto; padding: 0 24px; }
.narrow { max-width: 760px; }
/* ---------- hero ---------- */
.hero {
padding: 72px 24px 40px;
text-align: center;
padding: 56px 24px 24px;
}
.hero-grid {
display: grid;
grid-template-columns: minmax(0, 1.05fr) minmax(280px, 0.95fr);
gap: 56px;
align-items: center;
max-width: 1120px;
margin: 0 auto;
}
@media (max-width: 900px) {
.hero-grid { grid-template-columns: 1fr; gap: 40px; }
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 12.5px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--brass);
margin-bottom: 18px;
}
.eyebrow::before {
content: "";
width: 7px; height: 7px;
border-radius: 50%;
background: var(--brass);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--brass) 25%, transparent);
}
.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;
font-family: var(--font-display);
font-size: clamp(38px, 5.4vw, 68px);
font-weight: 600;
letter-spacing: -0.02em;
line-height: 1.02;
margin: 0 0 22px;
color: var(--fg);
}
.hero h1 em {
font-style: italic;
color: var(--seal);
}
.hero p.lead {
color: var(--muted);
font-size: 18px;
max-width: 620px;
margin: 0 auto 30px;
font-size: 17.5px;
max-width: 480px;
margin: 0 0 30px;
}
.cta-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.cta-row { display: flex; gap: 12px; flex-wrap: wrap; }
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 12px 22px;
border-radius: 10px;
padding: 13px 24px;
border-radius: 11px;
font-weight: 600;
font-size: 14.5px;
border: 1px solid var(--border);
border: 1px solid var(--line-strong);
transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}
.btn.primary {
background: linear-gradient(135deg, var(--accent), var(--accent2));
color: white;
background: linear-gradient(160deg, var(--seal), var(--seal-deep));
color: #ffffff;
border: none;
box-shadow: 0 12px 28px color-mix(in srgb, var(--seal) 35%, transparent);
}
.btn.primary:hover { opacity: 0.92; text-decoration: none; }
.btn.primary:hover { transform: translateY(-1px); text-decoration: none; }
.btn.secondary { color: var(--fg); }
.btn.secondary:hover { background: var(--bg-elevated); text-decoration: none; }
.btn.secondary:hover { background: var(--ink-soft); text-decoration: none; transform: translateY(-1px); }
/* ---------- signature visual: one credential, many doors ---------- */
.credential-scene {
position: relative;
display: grid;
gap: 14px;
justify-items: stretch;
}
.credential-card {
position: relative;
background: linear-gradient(155deg, var(--paper), var(--paper-dim));
color: #241d12;
border-radius: 16px;
padding: 20px 22px;
box-shadow: var(--shadow);
border: 1px solid color-mix(in srgb, var(--brass) 40%, transparent);
z-index: 2;
}
.credential-card .cc-top {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
}
.credential-card .cc-seal {
width: 30px; height: 30px;
border-radius: 50%;
background: linear-gradient(155deg, var(--seal), var(--seal-deep));
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
box-shadow: inset 0 0 0 2px rgba(255,255,255,0.35);
}
.credential-card .cc-seal svg { width: 15px; height: 15px; }
.credential-card .cc-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: #6b5a34; font-weight: 700; }
.credential-card .cc-name { font-family: var(--font-display); font-size: 17px; font-weight: 600; }
.credential-card .cc-id {
font-family: var(--font-mono);
font-size: 11.5px;
color: #6b5a34;
letter-spacing: 0.01em;
word-break: break-all;
}
.door-rail {
position: relative;
background: var(--ink-soft);
border: 1px solid var(--line);
border-radius: 16px;
padding: 8px;
display: grid;
gap: 4px;
z-index: 1;
}
.door-row {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 11px;
}
.door-row .door-icon {
width: 30px; height: 30px;
border-radius: 8px;
background: var(--ink-softer);
border: 1px solid var(--line);
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
color: var(--muted);
}
.door-row .door-icon svg { width: 16px; height: 16px; }
.door-row .door-label { font-size: 13.5px; color: var(--fg); font-weight: 550; flex: 1; }
.door-row .door-stamp {
width: 22px; height: 22px;
border-radius: 50%;
border: 1.5px solid var(--line-strong);
display: flex; align-items: center; justify-content: center;
flex-shrink: 0;
color: transparent;
background: transparent;
animation: stamp-in 0.5s ease-out both;
animation-delay: calc(var(--stamp-order, 0) * 0.32s + 0.5s);
}
.door-row .door-stamp svg { width: 12px; height: 12px; }
@keyframes stamp-in {
0% { transform: scale(1.7); border-color: var(--line-strong); color: transparent; background: transparent; }
55% { transform: scale(0.92); }
70% { border-color: var(--brass); background: color-mix(in srgb, var(--brass) 22%, transparent); color: var(--brass); }
100% { transform: scale(1); border-color: var(--brass); background: color-mix(in srgb, var(--brass) 22%, transparent); color: var(--brass); }
}
@media (prefers-reduced-motion: reduce) {
.door-row .door-stamp {
animation: none;
border-color: var(--brass);
background: color-mix(in srgb, var(--brass) 22%, transparent);
color: var(--brass);
}
}
.credential-scene .scene-caption {
text-align: center;
font-size: 12.5px;
color: var(--muted);
padding-top: 2px;
}
/* ---------- compare section ---------- */
.compare-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin: 36px 0 8px;
}
@media (max-width: 800px) {
.compare-grid { grid-template-columns: 1fr; }
}
.compare-card {
background: var(--ink-soft);
border: 1px solid var(--line);
border-radius: 16px;
padding: 22px;
}
.compare-card h3 { margin: 0 0 4px; font-size: 15.5px; font-family: var(--font-display); font-weight: 600; }
.compare-card .compare-kicker { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--muted); margin-bottom: 6px; display: block; }
.compare-card p { margin: 0; color: var(--muted); font-size: 13.5px; }
.compare-card.is-bitlogin {
background: linear-gradient(165deg, color-mix(in srgb, var(--seal) 16%, var(--ink-soft)), var(--ink-soft));
border-color: color-mix(in srgb, var(--brass) 55%, var(--line));
box-shadow: 0 18px 40px color-mix(in srgb, var(--seal) 18%, transparent);
transform: translateY(-6px);
}
@media (max-width: 800px) {
.compare-card.is-bitlogin { transform: none; }
}
.compare-card.is-bitlogin .compare-kicker { color: var(--brass); }
.compare-card.is-bitlogin p { color: var(--fg); opacity: 0.85; }
/* ---------- diagram (kept for docs/account pages) ---------- */
.diagram {
display: flex;
align-items: center;
@@ -109,16 +320,17 @@ a:hover { text-decoration: underline; }
font-size: 13.5px;
}
.diagram .step {
background: var(--bg-elevated);
border: 1px solid var(--border);
background: var(--ink-soft);
border: 1px solid var(--line);
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; }
.diagram .arrow { color: var(--brass); font-size: 18px; }
/* ---------- feature grid ---------- */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
@@ -126,32 +338,40 @@ a:hover { text-decoration: underline; }
margin: 40px 0;
}
.feature {
background: var(--bg-elevated);
border: 1px solid var(--border);
background: var(--ink-soft);
border: 1px solid var(--line);
border-radius: 14px;
padding: 20px;
transition: border-color 0.15s ease, transform 0.15s ease;
}
.feature h3 { margin: 0 0 8px; font-size: 15.5px; }
.feature:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.feature h3 { margin: 0 0 8px; font-size: 15.5px; font-family: var(--font-display); font-weight: 600; }
.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; }
h2 {
font-family: var(--font-display);
font-size: 30px;
font-weight: 600;
letter-spacing: -0.01em;
margin: 0 0 6px;
}
p.section-sub { color: var(--muted); margin: 0 0 28px; max-width: 620px; }
pre {
background: var(--code-bg);
color: #e8e6f5;
border: 1px solid var(--border);
color: #ece8f5;
border: 1px solid var(--line);
border-radius: 12px;
padding: 18px;
overflow-x: auto;
font-size: 13px;
line-height: 1.55;
}
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
code { font-family: var(--font-mono); }
:not(pre) > code {
background: var(--bg-elevated);
border: 1px solid var(--border);
background: var(--ink-soft);
border: 1px solid var(--line);
border-radius: 5px;
padding: 1px 5px;
font-size: 0.92em;
@@ -162,7 +382,7 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
counter-increment: step;
position: relative;
padding: 0 0 28px 44px;
border-left: 2px solid var(--border);
border-left: 2px solid var(--line);
margin-left: 15px;
}
.step-list > li:last-child { border-left-color: transparent; padding-bottom: 0; }
@@ -173,7 +393,7 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
top: 0;
width: 28px; height: 28px;
border-radius: 50%;
background: linear-gradient(135deg, var(--accent), var(--accent2));
background: linear-gradient(155deg, var(--seal), var(--seal-deep));
color: white;
font-weight: 700;
font-size: 13px;
@@ -181,11 +401,11 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
align-items: center;
justify-content: center;
}
.step-list h3 { margin: 2px 0 8px; font-size: 16px; }
.step-list h3 { margin: 2px 0 8px; font-size: 16px; font-family: var(--font-display); font-weight: 600; }
.callout {
border: 1px solid var(--border);
background: var(--bg-elevated);
border: 1px solid var(--line);
background: var(--ink-soft);
border-radius: 12px;
padding: 14px 16px;
font-size: 13.5px;
@@ -198,20 +418,26 @@ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
display: flex;
justify-content: center;
padding: 48px 24px 80px;
gap: 40px;
}
.app-layout .side {
max-width: 340px;
margin-right: 40px;
}
.app-layout .side h1 { font-size: 26px; margin: 0 0 10px; }
.app-layout .side h1 {
font-family: var(--font-display);
font-size: 30px;
font-weight: 600;
margin: 0 0 10px;
letter-spacing: -0.01em;
}
.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; }
.app-layout { flex-direction: column; align-items: center; gap: 24px; }
.app-layout .side { max-width: 460px; text-align: center; }
}
footer {
border-top: 1px solid var(--border);
border-top: 1px solid var(--line);
padding: 28px 24px;
text-align: center;
color: var(--muted);
+17 -4
View File
@@ -7,12 +7,24 @@
<meta name="description" content="How to add the BitLogin login widget to any static site in a few minutes." />
<link rel="icon" href="./assets/icon.svg" type="image/svg+xml" />
<link rel="manifest" href="./manifest.webmanifest" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,500;0,9..144,600;1,9..144,500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="./assets/site.css" />
</head>
<body>
<nav class="nav">
<a class="brand" href="./index.html"><span class="dot"></span>BitLogin</a>
<a class="brand" href="./index.html">
<span class="dot">
<svg viewBox="0 0 64 64" aria-hidden="true">
<circle cx="32" cy="32" r="30" fill="none" stroke="#d1a85a" stroke-width="4" />
<circle cx="32" cy="32" r="20" fill="#8368ff" />
<path d="M22 32.5l7 7 13-14.5" fill="none" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
BitLogin
</a>
<div class="links">
<a href="./index.html">Overview</a>
<a class="active" href="./docs.html">Integrate</a>
@@ -20,9 +32,10 @@
</div>
</nav>
<header class="hero" style="padding-top:48px">
<h1 style="font-size:38px">Add BitLogin to your site</h1>
<p class="lead">No npm install required. Two files, one custom element.</p>
<header class="hero" style="padding-top:48px; padding-bottom:8px">
<span class="eyebrow">Integration guide</span>
<h1 style="font-size:clamp(32px, 4.5vw, 44px)">Add BitLogin to your site</h1>
<p class="lead" style="max-width:520px">No npm install required. Two files, one custom element — and every user who already has a BitLogin account elsewhere can sign in with the login they already know.</p>
</header>
<section class="container narrow">
+107 -27
View File
@@ -3,16 +3,28 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>BitLogin — a portable login for the open web</title>
<meta name="description" content="A familiar login name and password that unlocks a portable Nostr identity, stored as encrypted capsules across public relays. No account server required." />
<title>BitLogin — one login for every site that uses it</title>
<meta name="description" content="A login name and password that work on every BitLogin site — no extension to install, no separate signer to keep running. Built on the open Nostr network, with no account server anyone can shut down." />
<link rel="icon" href="./assets/icon.svg" type="image/svg+xml" />
<link rel="manifest" href="./manifest.webmanifest" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,500;0,9..144,600;1,9..144,500&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="./assets/site.css" />
</head>
<body>
<nav class="nav">
<a class="brand" href="./index.html"><span class="dot"></span>BitLogin</a>
<a class="brand" href="./index.html">
<span class="dot">
<svg viewBox="0 0 64 64" aria-hidden="true">
<circle cx="32" cy="32" r="30" fill="none" stroke="#d1a85a" stroke-width="4" />
<circle cx="32" cy="32" r="20" fill="#8368ff" />
<path d="M22 32.5l7 7 13-14.5" fill="none" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
BitLogin
</a>
<div class="links">
<a class="active" href="./index.html">Overview</a>
<a href="./docs.html">Integrate</a>
@@ -21,58 +33,126 @@
</nav>
<header class="hero">
<h1>A login your users<br />actually take with them.</h1>
<p class="lead">
Login name and password on the outside. A portable Nostr identity underneath —
encrypted and stored on public relays, with no account server, no password-reset
email, and no vendor lock-in.
</p>
<div class="cta-row">
<a class="btn primary" href="./account.html">Try the demo →</a>
<a class="btn secondary" href="./docs.html">Add it to your site</a>
<div class="hero-grid">
<div>
<span class="eyebrow">One login. Every BitLogin site.</span>
<h1>One password.<br />Every door it <em>opens</em>.</h1>
<p class="lead">
Create a BitLogin account on any site that supports it, and the same login name
and password sign you into every other one. No new account to make, no extension
to install, no separate signer app to keep paired and running.
</p>
<div class="cta-row">
<a class="btn primary" href="./account.html">Try the demo →</a>
<a class="btn secondary" href="./docs.html">Add it to your site</a>
</div>
</div>
<div class="credential-scene" aria-hidden="true">
<div class="credential-card">
<div class="cc-top">
<span class="cc-seal">
<svg viewBox="0 0 24 24" fill="none"><path d="M6 12.5l4 4 8-9" stroke="#fff" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
<div>
<div class="cc-label">One credential</div>
<div class="cc-name">river&thinsp;·&thinsp;a few good words</div>
</div>
</div>
<div class="cc-id">npub1a3x…f92e</div>
</div>
<div class="door-rail">
<div class="door-row" style="--stamp-order:0">
<span class="door-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M4 9l8-5 8 5v10H4V9z" stroke="currentColor" stroke-width="1.6"/></svg></span>
<span class="door-label">Marketplace</span>
<span class="door-stamp"><svg viewBox="0 0 24 24" fill="none"><path d="M5 12l4 4 10-10" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</div>
<div class="door-row" style="--stamp-order:1">
<span class="door-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M4 5h16v10H8l-4 4V5z" stroke="currentColor" stroke-width="1.6"/></svg></span>
<span class="door-label">Community forum</span>
<span class="door-stamp"><svg viewBox="0 0 24 24" fill="none"><path d="M5 12l4 4 10-10" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</div>
<div class="door-row" style="--stamp-order:2">
<span class="door-icon"><svg viewBox="0 0 24 24" fill="none"><rect x="4" y="4" width="16" height="16" rx="2" stroke="currentColor" stroke-width="1.6"/><path d="M4 9h16" stroke="currentColor" stroke-width="1.6"/></svg></span>
<span class="door-label">Personal blog</span>
<span class="door-stamp"><svg viewBox="0 0 24 24" fill="none"><path d="M5 12l4 4 10-10" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</div>
<div class="door-row" style="--stamp-order:3">
<span class="door-icon"><svg viewBox="0 0 24 24" fill="none"><path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6l7-3z" stroke="currentColor" stroke-width="1.6"/></svg></span>
<span class="door-label">Your site, next</span>
<span class="door-stamp"><svg viewBox="0 0 24 24" fill="none"><path d="M5 12l4 4 10-10" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
</div>
</div>
<div class="scene-caption">Same login name and password. Every site that speaks BitLogin.</div>
</div>
</div>
</header>
<section class="container">
<h2>What actually happens at sign-in</h2>
<p class="section-sub">No account database to breach, no password-reset email to intercept — just math, run locally, every time.</p>
<div class="diagram">
<div class="step"><div class="k">Everyday login</div>Login name + password</div>
<div class="arrow">→</div>
<div class="step"><div class="k">Locally derived</div>Password-locked locator key</div>
<div class="arrow">→</div>
<div class="step"><div class="k">Public relays</div>Encrypted capsule lookup</div>
<div class="step"><div class="k">Public network</div>Encrypted capsule lookup</div>
<div class="arrow">→</div>
<div class="step"><div class="k">Result</div>Portable Nostr identity</div>
<div class="step"><div class="k">Result</div>Your portable identity, unlocked</div>
</div>
</header>
</section>
<section class="container">
<h2>Two independent ways in, one identity</h2>
<p class="section-sub">Forgetting a password and losing a device are different emergencies. BitLogin keeps them cryptographically separate.</p>
<div class="grid">
<div class="feature">
<h3>🔑 Password path</h3>
<p>Login name + password deterministically derive a private "locator" key and an encryption key. That key finds and decrypts a small credential capsule on public relays — no lookup table, no server, no email.</p>
<h3>Password path</h3>
<p>Login name + password deterministically derive a private "locator" key and an encryption key. That key finds and decrypts a small credential capsule — no lookup table, no server, no email.</p>
</div>
<div class="feature">
<h3>🌱 Recovery phrase</h3>
<h3>Recovery phrase</h3>
<p>A 12-word phrase derives a completely independent recovery identity. A cracked password can never sign, replace, or delete the recovery capsule — it has no authority over that path at all.</p>
</div>
<div class="feature">
<h3>🪪 One everyday identity</h3>
<p>Both paths unlock the exact same everyday Nostr keypair — your real, canonical, portable identity. Change your password as often as you like; the identity never moves.</p>
<h3>One everyday identity</h3>
<p>Both paths unlock the exact same everyday keypair — your real, canonical, portable identity. Change your password as often as you like; the identity underneath never moves.</p>
</div>
</div>
</section>
<section class="container">
<h2>Not a browser extension. Not a remote signer.</h2>
<p class="section-sub">Both of those are good tools for the people already running them. BitLogin exists for everyone else.</p>
<div class="compare-grid">
<div class="compare-card">
<span class="compare-kicker">A browser extension (NIP-07)</span>
<h3>Lives in one browser</h3>
<p>Sign in on your phone, at work, or in a private window, and you're locked out — the keys never left that one browser profile.</p>
</div>
<div class="compare-card">
<span class="compare-kicker">A remote signer (NIP-46)</span>
<h3>Needs another device online</h3>
<p>Every sign-in bounces through a separate signing app or "bunker" that you have to keep running, paired, and reachable.</p>
</div>
<div class="compare-card is-bitlogin">
<span class="compare-kicker">BitLogin</span>
<h3>Just a login name and password</h3>
<p>The two things you already remember. Nothing to install, nothing else to keep online, works the same on any device or browser.</p>
</div>
</div>
</section>
<section class="container">
<h2>Why this is different</h2>
<p class="section-sub">Every design choice traces back to one constraint: it has to work with nothing but static files and public relays.</p>
<p class="section-sub">Every design choice traces back to one constraint: it has to work with nothing but static files and a public network.</p>
<div class="grid">
<div class="feature">
<h3>Static-first</h3>
<p>The whole client — crypto, UI, worker — ships as files. Host it anywhere: Pages, IPFS, a folder on a CDN. No backend to run or pay for.</p>
</div>
<div class="feature">
<h3>Relay-redundant storage</h3>
<p>Encrypted capsules are published to multiple Nostr relays with quorum reads and readback verification, so no single relay is a single point of failure.</p>
<h3>No single point of failure</h3>
<p>Encrypted capsules are published to multiple independent relays with quorum reads and readback verification, so losing any one of them doesn't lock anyone out.</p>
</div>
<div class="feature">
<h3>Generated by default, never weak</h3>
@@ -80,15 +160,15 @@
</div>
<div class="feature">
<h3>Argon2id + AES-256-GCM</h3>
<p>Memory-hard key derivation, authenticated encryption, canonical JSON serialization, and fixed padding buckets so ciphertext size doesn't leak contents.</p>
<p>Memory-hard key derivation, authenticated encryption, canonical serialization, and fixed padding buckets so ciphertext size doesn't leak contents.</p>
</div>
<div class="feature">
<h3>Rollback-resistant</h3>
<p>A local generation high-water mark and monotonic timestamps mean a stale or malicious relay can't quietly roll a logged-in device back to an older capsule.</p>
</div>
<div class="feature">
<h3>NIP-07-compatible signing</h3>
<p>Once unlocked, BitLogin exposes a <code>window.nostr</code> provider — the same shape browser extensions use. Existing Nostr apps work with zero code changes.</p>
<h3>Works with existing Nostr apps</h3>
<p>Once unlocked, BitLogin quietly plugs into the same <code>window.nostr</code> interface browser extensions use — apps built for those work with zero code changes.</p>
</div>
</div>
</section>
@@ -102,7 +182,7 @@
</section>
<footer>
BitLogin is an experimental alpha protocol. This demo is a reference implementation, not a production account service.
BitLogin is an experimental alpha protocol, built on the open Nostr network. This demo is a reference implementation, not a production account service.
<div class="footer-links"><a href="https://github.com/PR0M3TH3AN/bitlogin">Source on GitHub</a> · MIT licensed — <a href="https://github.com/PR0M3TH3AN/bitlogin/blob/main/LICENSE">LICENSE</a></div>
</footer>