0e7c413825
Static HTML + SVG/PNG assets for the public marketing site at keysat.xyz. Deployed via FileBrowser to the operator's StartOS at websites/keysat-xyz-landing/. Files: - index.html — main landing - support.html — Lightning donation + on-chain BTC for sponsors - assets/ — SVG marks, PNG icon/thumbnail, favicon Stack: hand-written HTML + CSS, no build step, no JS framework. Matches the keysat-design-system tokens (cream paper, navy ink, gold accents, Archivo display + Inter body + JetBrains Mono). Private repo during alpha; will go public alongside v1.0 launch.
1009 lines
48 KiB
HTML
1009 lines
48 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Keysat — Bitcoin-paid software licensing, self-hosted on Start9</title>
|
|
<meta name="description" content="Keysat is a self-hosted licensing service for independent creators who want to monetize the software they build. Runs on Start9. Pays in Bitcoin or fiat. Verifies offline.">
|
|
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
|
|
|
|
<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=Manrope:wght@400;500;600;700;900&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
|
|
<style>
|
|
:root {
|
|
/* ---------- Brand ---------- */
|
|
--navy-950:#0E1F33; --navy-900:#142A47; --navy-800:#1E3A5F; --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-50:#FBF9F2; --cream-100:#F5F1E8; --cream-200:#EDE7D7; --cream-300:#E1D8C0;
|
|
--cream-400:#C9BC9A;
|
|
--gold-700:#8A6F3D; --gold-600:#A88652; --gold-500:#BFA068; --gold-400:#D4B985;
|
|
--gold-300:#E5CFA5; --gold-200:#F0E2C5;
|
|
--ink-900:#0E1F33; --ink-700:#2C3E54; --ink-500:#5A6B7F; --ink-400:#7E8C9D; --ink-300:#A4AEBB;
|
|
--success:#2D7A5F; --success-bg:#E3F0EA;
|
|
--warning:#B8861F; --warning-bg:#F7EFD7;
|
|
--danger:#B23A3A; --danger-bg:#F4E0E0;
|
|
--border-1:rgba(14,31,51,0.12);
|
|
--border-2:rgba(14,31,51,0.20);
|
|
--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;
|
|
--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);
|
|
--ease-standard:cubic-bezier(0.2,0.7,0.2,1);
|
|
}
|
|
|
|
* { box-sizing:border-box; }
|
|
html, body { margin:0; padding:0; }
|
|
body {
|
|
font-family:var(--font-body);
|
|
color:var(--ink-900);
|
|
background:var(--cream-100);
|
|
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;
|
|
-webkit-font-smoothing:antialiased;
|
|
-moz-osx-font-smoothing:grayscale;
|
|
}
|
|
.wrap { max-width:1180px; margin:0 auto; padding:0 32px; }
|
|
a { color:var(--ink-900); text-decoration:none; }
|
|
a:hover { color:var(--navy-900); }
|
|
|
|
/* ---------- Header ---------- */
|
|
header.site {
|
|
position:sticky; top:0; z-index:20;
|
|
background:rgba(245,241,232,0.85);
|
|
backdrop-filter:blur(12px);
|
|
border-bottom:1px solid var(--border-1);
|
|
}
|
|
header.site .inner { display:flex; align-items:center; gap:28px; padding:16px 0; }
|
|
header.site .brand {
|
|
display:flex; align-items:center; gap:10px;
|
|
font-family:var(--font-display); font-weight:500; font-size:15px;
|
|
letter-spacing:0.30em; text-transform:uppercase; color:var(--navy-900);
|
|
}
|
|
header.site .brand img { width:32px; height:32px; }
|
|
header.site nav { margin-left:auto; display:flex; gap:28px; font-size:14px; }
|
|
header.site nav a { color:var(--ink-700); font-weight:500; }
|
|
header.site nav a:hover { color:var(--navy-900); }
|
|
header.site .cta { margin-left:8px; }
|
|
|
|
/* ---------- Buttons ---------- */
|
|
.btn {
|
|
display:inline-flex; align-items:center; gap:8px;
|
|
font-family:var(--font-body); font-weight:600; font-size:14px;
|
|
padding:11px 20px; border-radius:8px; border:1px solid transparent;
|
|
cursor:pointer; transition:all 120ms var(--ease-standard); line-height:1;
|
|
text-decoration:none;
|
|
}
|
|
.btn.lg { font-size:15.5px; padding:14px 24px; }
|
|
.btn.primary { background:var(--navy-800); color:var(--cream-50); border-color:var(--navy-800); }
|
|
.btn.primary:hover { background:var(--navy-900); border-color:var(--navy-900); color:var(--cream-50); }
|
|
.btn.secondary { background:transparent; color:var(--navy-900); border-color:var(--border-2); }
|
|
.btn.secondary:hover { background:var(--cream-200); color:var(--navy-900); }
|
|
.btn.ghost { background:transparent; color:var(--navy-900); border:none; }
|
|
.btn.ghost:hover { background:rgba(14,31,51,0.06); }
|
|
.btn .arrow { transition:transform 200ms var(--ease-standard); }
|
|
.btn:hover .arrow { transform:translateX(2px); }
|
|
|
|
/* ---------- Hero ---------- */
|
|
section.hero { padding:92px 0 72px; }
|
|
.hero-grid { display:grid; grid-template-columns:1.15fr 1fr; gap:64px; align-items:center; }
|
|
.hero .eyebrow {
|
|
font-size:11.5px; font-weight:700; letter-spacing:0.18em;
|
|
text-transform:uppercase; color:var(--gold-700);
|
|
display:inline-flex; align-items:center; gap:10px; margin-bottom:22px;
|
|
}
|
|
.hero .eyebrow::before {
|
|
content:''; display:inline-block; width:28px; height:1px; background:var(--gold-500);
|
|
}
|
|
.hero h1 {
|
|
font-family:var(--font-display);
|
|
font-size:clamp(44px, 5.4vw, 72px);
|
|
font-weight:500; line-height:1.02;
|
|
letter-spacing:-0.022em; color:var(--navy-950);
|
|
margin:0 0 22px; text-wrap:balance;
|
|
}
|
|
.hero h1 .gold {
|
|
background-image:linear-gradient(to top, var(--gold-400) 0, var(--gold-400) 6px, transparent 6px);
|
|
background-repeat:no-repeat; background-position:0 95%; padding-bottom:2px;
|
|
}
|
|
.hero p.lede {
|
|
font-size:19px; line-height:1.55; color:var(--ink-700);
|
|
max-width:540px; margin:0 0 32px;
|
|
}
|
|
.hero .cta-row { display:flex; gap:12px; align-items:center; flex-wrap:wrap; }
|
|
.hero .trust {
|
|
margin-top:36px; display:flex; align-items:center; gap:18px;
|
|
font-size:13px; color:var(--ink-500); flex-wrap:wrap;
|
|
}
|
|
.hero .trust span { display:inline-flex; align-items:center; gap:7px; }
|
|
.hero .trust .dot { width:4px; height:4px; border-radius:50%; background:var(--gold-500); }
|
|
.hero .trust [data-lucide] { color:var(--navy-700); }
|
|
|
|
/* Hero certificate visual */
|
|
.cert {
|
|
background:var(--cream-50);
|
|
border:1px solid var(--border-1);
|
|
border-radius:14px;
|
|
box-shadow:0 0 0 1px var(--gold-500) inset, 0 8px 16px rgba(14,31,51,0.10), 0 24px 64px rgba(14,31,51,0.10);
|
|
padding:36px 36px 30px;
|
|
position:relative;
|
|
transform:rotate(-1.2deg);
|
|
max-width:460px;
|
|
margin-left:auto;
|
|
}
|
|
.cert::before, .cert::after {
|
|
content:''; position:absolute; left:16px; right:16px;
|
|
height:1px; background:var(--gold-500); opacity:0.5;
|
|
}
|
|
.cert::before { top:16px; } .cert::after { bottom:16px; }
|
|
.cert .seal {
|
|
position:absolute; right:-30px; top:-30px;
|
|
width:88px; height:88px; border-radius:50%;
|
|
background:var(--cream-50);
|
|
box-shadow:0 0 0 1px var(--gold-500) inset, 0 0 0 5px var(--cream-50), 0 0 0 6px var(--gold-500), var(--shadow-md);
|
|
display:flex; align-items:center; justify-content:center;
|
|
font-family:var(--font-display); font-weight:900; font-size:32px; color:var(--navy-800);
|
|
transform:rotate(8deg);
|
|
}
|
|
.cert .stamp {
|
|
font-size:9.5px; font-weight:700; letter-spacing:0.22em;
|
|
text-transform:uppercase; color:var(--gold-700);
|
|
text-align:center; margin-bottom:14px;
|
|
}
|
|
.cert h4 {
|
|
font-family:var(--font-display); font-weight:500; font-size:22px;
|
|
text-align:center; color:var(--navy-900); margin:0 0 4px; letter-spacing:-0.015em;
|
|
}
|
|
.cert .sub { text-align:center; font-size:12px; color:var(--ink-500); margin-bottom:22px; }
|
|
.cert .field { font-size:11px; font-weight:600; letter-spacing:0.12em; text-transform:uppercase; color:var(--ink-500); margin-bottom:4px; }
|
|
.cert .value { font-family:var(--font-mono); font-size:14px; color:var(--navy-900); margin-bottom:14px; }
|
|
.cert .row { display:grid; grid-template-columns:1fr 1fr; gap:18px; }
|
|
.cert .sig {
|
|
border-top:1px dashed rgba(14,31,51,0.2);
|
|
padding-top:12px; margin-top:6px;
|
|
font-family:var(--font-mono); font-size:10.5px; color:var(--ink-500);
|
|
line-height:1.5; word-break:break-all;
|
|
}
|
|
|
|
/* ---------- Sections ---------- */
|
|
section.block { padding:96px 0; }
|
|
section.tinted { background:var(--cream-200); position:relative; }
|
|
section.tinted::before, section.tinted::after {
|
|
content:''; position:absolute; left:0; right:0; height:1px; background:var(--gold-500); opacity:0.4;
|
|
}
|
|
section.tinted::before { top:0; } section.tinted::after { bottom:0; }
|
|
|
|
.section-head { max-width:760px; margin-bottom:56px; }
|
|
.section-head .eyebrow {
|
|
font-size:11.5px; font-weight:700; letter-spacing:0.18em;
|
|
text-transform:uppercase; color:var(--gold-700); margin-bottom:14px; display:block;
|
|
}
|
|
.section-head h2 {
|
|
font-family:var(--font-display);
|
|
font-size:clamp(32px, 3.6vw, 46px);
|
|
font-weight:500; line-height:1.05; letter-spacing:-0.022em;
|
|
color:var(--navy-950); margin:0 0 14px;
|
|
}
|
|
.section-head p { font-size:18px; line-height:1.55; color:var(--ink-700); margin:0; max-width:580px; }
|
|
|
|
/* ---------- Value grid ---------- */
|
|
.value-grid {
|
|
display:grid; grid-template-columns:repeat(3, 1fr); gap:1px;
|
|
background:var(--border-1); border:1px solid var(--border-1);
|
|
border-radius:14px; overflow:hidden;
|
|
}
|
|
.value-grid .item { background:var(--cream-50); padding:32px 28px; transition:background 150ms; }
|
|
.value-grid .item:hover { background:var(--cream-100); }
|
|
.value-grid .icon-wrap {
|
|
width:40px; height:40px; border-radius:8px;
|
|
background:var(--cream-200); border:1px solid var(--border-1);
|
|
display:flex; align-items:center; justify-content:center;
|
|
margin-bottom:18px; color:var(--navy-800);
|
|
}
|
|
.value-grid h3 {
|
|
font-family:var(--font-display); font-weight:700; font-size:18px;
|
|
color:var(--navy-950); margin:0 0 6px; letter-spacing:-0.01em;
|
|
}
|
|
.value-grid h3 + .accent-bar { width:22px; height:2px; background:var(--gold-500); margin-bottom:12px; }
|
|
.value-grid p { margin:0; font-size:14.5px; color:var(--ink-700); line-height:1.55; }
|
|
|
|
/* ---------- Flow ---------- */
|
|
.flow { display:grid; grid-template-columns:repeat(5, 1fr); gap:16px; list-style:none; padding:0; margin:0; }
|
|
.flow .step {
|
|
background:var(--cream-50); border:1px solid var(--border-1);
|
|
border-radius:12px; padding:28px 22px 24px;
|
|
position:relative; box-shadow:var(--shadow-sm);
|
|
}
|
|
.flow .num {
|
|
font-family:var(--font-display); font-weight:900; font-size:56px;
|
|
color:var(--gold-500); line-height:1; margin-bottom:14px;
|
|
letter-spacing:-0.04em; font-variant-numeric:lining-nums;
|
|
}
|
|
.flow .step h3 {
|
|
font-family:var(--font-display); font-weight:700; font-size:16px;
|
|
color:var(--navy-950); margin:0 0 6px; letter-spacing:-0.01em; line-height:1.25;
|
|
}
|
|
.flow .step p { font-size:13.5px; color:var(--ink-700); line-height:1.5; margin:0; }
|
|
.flow .step code { font-family:var(--font-mono); font-size:0.92em; padding:1px 5px; background:var(--cream-200); border-radius:4px; color:var(--navy-900); }
|
|
|
|
/* ---------- Code section ---------- */
|
|
.code-card {
|
|
background:var(--navy-950); border-radius:14px; overflow:hidden;
|
|
box-shadow:var(--shadow-lg); border:1px solid var(--navy-900);
|
|
}
|
|
.code-tabs {
|
|
display:flex; background:var(--navy-900);
|
|
border-bottom:1px solid rgba(245,241,232,0.08);
|
|
padding:0 8px;
|
|
}
|
|
.code-tabs button {
|
|
background:transparent; border:0;
|
|
color:rgba(245,241,232,0.55);
|
|
font-family:var(--font-body); font-weight:500; font-size:13px;
|
|
padding:14px 18px; cursor:pointer;
|
|
border-bottom:2px solid transparent;
|
|
transition:color 120ms;
|
|
}
|
|
.code-tabs button:hover { color:rgba(245,241,232,0.85); }
|
|
.code-tabs button.active { color:var(--cream-50); border-bottom-color:var(--gold-500); }
|
|
.code-tabs .install {
|
|
margin-left:auto; padding:14px 18px;
|
|
font-family:var(--font-mono); font-size:12px;
|
|
color:var(--gold-400);
|
|
}
|
|
pre.code {
|
|
margin:0; padding:24px 28px;
|
|
font-family:var(--font-mono); font-size:13.5px;
|
|
line-height:1.7; color:var(--cream-50); overflow-x:auto;
|
|
}
|
|
pre.code .c { color:rgba(245,241,232,0.45); }
|
|
pre.code .k { color:var(--gold-400); }
|
|
pre.code .s { color:#d4b985; }
|
|
pre.code .n { color:#a6b7cf; }
|
|
pre.code .f { color:var(--cream-50); }
|
|
pre.code .p { color:rgba(245,241,232,0.55); }
|
|
|
|
.code-section { display:grid; grid-template-columns:1fr 1fr; gap:56px; align-items:start; }
|
|
.code-section .pitch h3 { font-family:var(--font-display); font-weight:700; font-size:36px; line-height:1.1; letter-spacing:-0.022em; color:var(--navy-950); margin:14px 0 12px; }
|
|
.code-section .pitch p { font-size:16px; color:var(--ink-700); line-height:1.55; margin:0 0 16px; }
|
|
.code-section .pitch ul { list-style:none; padding:0; margin:24px 0 0; }
|
|
.code-section .pitch li { display:flex; align-items:start; gap:12px; padding:8px 0; font-size:14.5px; color:var(--ink-700); }
|
|
.code-section .pitch li::before { content:'\2713'; color:var(--gold-600); font-weight:700; flex-shrink:0; margin-top:1px; }
|
|
|
|
/* ---------- Sovereign ---------- */
|
|
.sov { display:grid; grid-template-columns:1fr 1fr; gap:24px; }
|
|
.sov .panel { background:var(--cream-50); border:1px solid var(--border-1); border-radius:14px; padding:32px 32px 28px; }
|
|
.sov .panel.dark { background:var(--navy-950); color:var(--cream-50); border:1px solid var(--navy-900); }
|
|
.sov .panel h3 { font-family:var(--font-display); font-weight:700; font-size:19px; margin:0 0 4px; letter-spacing:-0.015em; color:inherit; }
|
|
.sov .panel .sub { font-size:13px; color:var(--ink-500); margin-bottom:22px; }
|
|
.sov .panel.dark .sub { color:rgba(245,241,232,0.55); }
|
|
.sov ul { list-style:none; padding:0; margin:0; display:flex; flex-wrap:wrap; gap:8px; }
|
|
.sov li {
|
|
font-size:13px; padding:6px 13px; border-radius:999px;
|
|
background:var(--cream-100); border:1px solid var(--border-1); color:var(--ink-700);
|
|
}
|
|
.sov .panel.dark li {
|
|
background:var(--navy-900); border-color:rgba(245,241,232,0.15); color:rgba(245,241,232,0.9);
|
|
}
|
|
.sov .panel.dark li.no::before { content:'\2715 '; color:rgba(245,241,232,0.45); margin-right:2px; }
|
|
.sov .panel .footnote { font-size:13px; color:var(--ink-500); margin:18px 0 0; line-height:1.55; }
|
|
.sov .panel.dark .footnote { color:rgba(245,241,232,0.6); }
|
|
|
|
/* ---------- Install ---------- */
|
|
.install-grid { display:grid; grid-template-columns:1fr 1fr; gap:24px; }
|
|
.install-card { background:var(--cream-50); border:1px solid var(--border-1); border-radius:14px; padding:28px; }
|
|
.install-card.featured { box-shadow:0 0 0 1px var(--gold-500) inset, var(--shadow-sm); }
|
|
.install-card .cap {
|
|
display:inline-block; font-size:10.5px; font-weight:700;
|
|
letter-spacing:0.18em; text-transform:uppercase; color:var(--gold-700);
|
|
margin-bottom:12px;
|
|
}
|
|
.install-card h3 { font-family:var(--font-display); font-weight:700; font-size:22px; color:var(--navy-950); margin:0 0 8px; letter-spacing:-0.015em; }
|
|
.install-card p { font-size:14.5px; color:var(--ink-700); margin:0 0 16px; line-height:1.55; }
|
|
.cmd-card {
|
|
background:var(--navy-950); color:var(--cream-50);
|
|
border-radius:10px; padding:14px 16px;
|
|
font-family:var(--font-mono); font-size:13px;
|
|
display:flex; align-items:center; justify-content:space-between; gap:12px;
|
|
}
|
|
.cmd-card .copy {
|
|
background:rgba(245,241,232,0.10); color:var(--cream-50);
|
|
border:0; padding:6px 10px; border-radius:6px;
|
|
font-family:var(--font-body); font-size:11.5px; cursor:pointer;
|
|
transition:background 120ms;
|
|
}
|
|
.cmd-card .copy:hover { background:rgba(245,241,232,0.20); }
|
|
.install-card ol { padding-left:20px; margin:8px 0 0; color:var(--ink-700); font-size:14.5px; line-height:1.7; }
|
|
.install-card ol code { font-family:var(--font-mono); font-size:0.9em; padding:2px 5px; background:var(--cream-200); border-radius:4px; }
|
|
|
|
/* ---------- FAQ ---------- */
|
|
.faq { display:grid; grid-template-columns:1fr 1fr; gap:24px 56px; }
|
|
.faq h3 { font-family:var(--font-display); font-weight:700; font-size:17px; color:var(--navy-950); margin:0 0 6px; letter-spacing:-0.01em; }
|
|
.faq p { font-size:14.5px; color:var(--ink-700); line-height:1.55; margin:0 0 6px; }
|
|
.faq code { font-family:var(--font-mono); font-size:0.9em; padding:1px 5px; background:var(--cream-200); border-radius:4px; color:var(--navy-900); }
|
|
|
|
/* ---------- Footer ---------- */
|
|
footer.site {
|
|
background:var(--navy-950); color:var(--cream-300);
|
|
padding:56px 0 36px; border-top:1px solid var(--gold-500);
|
|
}
|
|
footer.site .top { display:flex; justify-content:space-between; flex-wrap:wrap; gap:36px; margin-bottom:36px; }
|
|
footer.site .col h5 {
|
|
font-family:var(--font-body); font-size:11.5px; font-weight:700;
|
|
letter-spacing:0.18em; text-transform:uppercase; color:var(--gold-400);
|
|
margin:0 0 14px;
|
|
}
|
|
footer.site .col a { display:block; color:rgba(245,241,232,0.7); padding:4px 0; font-size:14px; }
|
|
footer.site .col a:hover { color:var(--cream-50); }
|
|
footer.site .brand-block { max-width:320px; }
|
|
footer.site .brand {
|
|
display:flex; align-items:center; gap:10px;
|
|
font-family:var(--font-display); font-weight:500; font-size:15px;
|
|
letter-spacing:0.30em; text-transform:uppercase;
|
|
color:var(--cream-50); margin-bottom:14px;
|
|
}
|
|
footer.site .brand img { width:32px; height:32px; }
|
|
footer.site .tag { font-size:13.5px; line-height:1.55; color:rgba(245,241,232,0.65); margin:0; }
|
|
footer.site .bottom {
|
|
border-top:1px solid rgba(245,241,232,0.10);
|
|
padding-top:24px;
|
|
display:flex; justify-content:space-between; flex-wrap:wrap; gap:12px;
|
|
font-size:12.5px; color:rgba(245,241,232,0.45);
|
|
}
|
|
footer.site .bottom a { color:rgba(245,241,232,0.6); }
|
|
|
|
/* ---------- Creators slider (full-width, auto-advance) ---------- */
|
|
.case-section { padding-bottom: 96px; }
|
|
.case-slider {
|
|
position:relative; width:100%; overflow:hidden;
|
|
margin-top:24px;
|
|
background: var(--cream-50);
|
|
border-top: 1px solid var(--border-1);
|
|
border-bottom: 1px solid var(--border-1);
|
|
}
|
|
.case-track {
|
|
display:flex;
|
|
width:100%;
|
|
transition: transform 1s cubic-bezier(0.16, 1, 0.3, 1);
|
|
will-change: transform;
|
|
}
|
|
.case-slide {
|
|
flex: 0 0 100%; min-width: 100%;
|
|
display:grid; grid-template-columns: 1.1fr 1fr;
|
|
align-items:stretch;
|
|
min-height: 460px;
|
|
}
|
|
.case-slide .photo {
|
|
position:relative; overflow:hidden;
|
|
background: var(--cream-200);
|
|
border-right: 1px solid var(--border-1);
|
|
}
|
|
.case-slide .photo img {
|
|
width:100%; height:100%; object-fit:cover; object-position:center;
|
|
display:block;
|
|
}
|
|
.case-slide .photo .photo-fallback {
|
|
position:absolute; inset:0;
|
|
display:flex; align-items:center; justify-content:center;
|
|
flex-direction:column; gap:14px;
|
|
color: var(--ink-500);
|
|
background: linear-gradient(135deg, var(--cream-200) 0%, var(--cream-300) 100%);
|
|
text-align:center; padding: 24px;
|
|
}
|
|
.case-slide .photo .photo-fallback svg { width: 96px; height: 96px; opacity: 0.5; }
|
|
.case-slide .photo .photo-fallback .label {
|
|
font-size: 11.5px; font-weight: 700; letter-spacing: 0.16em;
|
|
text-transform: uppercase; color: var(--gold-700);
|
|
}
|
|
.case-slide .photo .photo-fallback .filename {
|
|
font-family: var(--font-mono); font-size: 11px;
|
|
color: var(--ink-500); padding: 4px 8px;
|
|
background: var(--cream-50); border: 1px solid var(--border-1);
|
|
border-radius: 5px;
|
|
}
|
|
.case-slide .body {
|
|
padding: 56px 56px 48px;
|
|
display:flex; flex-direction:column; justify-content:center; gap:18px;
|
|
background: var(--cream-50);
|
|
}
|
|
.case-slide .eyebrow-tag {
|
|
font-size:11.5px; font-weight:700; letter-spacing:0.18em;
|
|
text-transform:uppercase; color:var(--gold-700);
|
|
display:inline-flex; align-items:center; gap:10px;
|
|
}
|
|
.case-slide .eyebrow-tag::before {
|
|
content:''; display:inline-block; width:28px; height:1px; background:var(--gold-500);
|
|
}
|
|
.case-slide .name {
|
|
font-family: var(--font-display); font-weight:700; font-size: 28px;
|
|
color: var(--navy-950); letter-spacing:-0.02em; line-height:1.1;
|
|
margin: 0;
|
|
}
|
|
.case-slide .role {
|
|
font-size: 15px; color: var(--ink-500); line-height:1.5;
|
|
margin: 0;
|
|
}
|
|
.case-slide .product-block {
|
|
background: var(--cream-100);
|
|
border: 1px solid var(--border-1);
|
|
border-radius: 10px;
|
|
padding: 16px 18px;
|
|
display:flex; align-items:flex-start; gap:14px;
|
|
}
|
|
.case-slide .product-block .product-icon {
|
|
width: 22px; height: 22px; flex-shrink:0; margin-top: 2px; color: var(--gold-700);
|
|
}
|
|
.case-slide .product-block .product-name {
|
|
font-family: var(--font-display); font-weight:700; font-size: 16px;
|
|
color: var(--navy-950); letter-spacing:-0.01em; margin: 0 0 4px;
|
|
}
|
|
.case-slide .product-block .product-tag {
|
|
font-size: 13.5px; color: var(--ink-700); margin: 0; line-height: 1.5;
|
|
}
|
|
.case-slide blockquote {
|
|
margin: 0; padding: 0 0 0 18px;
|
|
font-family: var(--font-body); font-style: italic;
|
|
font-size: 17px; line-height: 1.55; color: var(--ink-700);
|
|
border-left: 3px solid var(--gold-500);
|
|
}
|
|
.case-slide .stats {
|
|
display:flex; gap: 32px;
|
|
padding-top: 18px; border-top: 1px dashed rgba(14,31,51,0.12);
|
|
font-size: 12px; color: var(--ink-500); letter-spacing:0.04em;
|
|
}
|
|
.case-slide .stats .stat-num {
|
|
font-family: var(--font-display); font-weight:700; font-size: 22px;
|
|
color: var(--navy-900); letter-spacing:-0.015em; display:block; margin-bottom: 2px;
|
|
}
|
|
|
|
/* Slider controls */
|
|
.case-controls {
|
|
display:flex; justify-content:center; align-items:center; gap: 8px;
|
|
padding: 24px 0 0;
|
|
}
|
|
.case-dot {
|
|
width: 8px; height: 8px; border-radius: 50%;
|
|
background: var(--border-2); border: 0; padding: 0;
|
|
cursor: pointer; transition: all 200ms;
|
|
}
|
|
.case-dot.active {
|
|
background: var(--navy-800);
|
|
width: 28px; border-radius: 4px;
|
|
}
|
|
.case-dot:hover { background: var(--navy-700); }
|
|
|
|
.case-section .footnote {
|
|
text-align:center; font-size:12px; color: var(--ink-500);
|
|
margin-top: 18px; letter-spacing:0.04em;
|
|
}
|
|
|
|
/* ---------- Responsive ---------- */
|
|
@media (max-width: 980px) {
|
|
.hero-grid { grid-template-columns:1fr; gap:48px; }
|
|
.cert { transform:none; max-width:100%; margin:0 auto; }
|
|
.value-grid { grid-template-columns:repeat(2, 1fr); }
|
|
.flow { grid-template-columns:repeat(2, 1fr); }
|
|
.code-section, .sov, .install-grid, .faq { grid-template-columns:1fr; }
|
|
header.site nav { display:none; }
|
|
section.block { padding:64px 0; }
|
|
|
|
/* Case slider: stack photo above content on narrow screens */
|
|
.case-slide { grid-template-columns: 1fr; min-height: auto; }
|
|
.case-slide .photo { min-height: 280px; border-right: 0; border-bottom: 1px solid var(--border-1); }
|
|
.case-slide .body { padding: 32px 24px 28px; }
|
|
.case-slide .name { font-size: 22px; }
|
|
.case-slide blockquote { font-size: 15px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<header class="site">
|
|
<div class="wrap inner">
|
|
<a class="brand" href="#top">
|
|
<img src="assets/keysat-mark.svg" alt="">
|
|
<span>Keysat</span>
|
|
</a>
|
|
<nav>
|
|
<a href="#why">Why</a>
|
|
<a href="#creators">Creators</a>
|
|
<a href="#how">How it works</a>
|
|
<a href="#integrate">Integrate</a>
|
|
<a href="#install">Install</a>
|
|
<a href="https://docs.keysat.xyz">Docs</a>
|
|
</nav>
|
|
<a href="https://licensing.keysat.xyz/buy/keysat" class="btn primary cta">Buy License</a>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="hero" id="top">
|
|
<div class="wrap hero-grid">
|
|
<div>
|
|
<div class="eyebrow">Software licensing for independent creators</div>
|
|
<h1>Bitcoin-paid software licensing, <span class="gold">self-hosted</span> on Start9.</h1>
|
|
<p class="lede">
|
|
Buyers pay in Bitcoin via your own BTCPay. Your software verifies signed keys offline. You own the signing key, the customer list, and the payment rails — no SaaS, no middleman, no platform risk.
|
|
</p>
|
|
<p class="lede" style="margin-top:14px; color:var(--ink-700); font-size:17px;">
|
|
Keysat empowers independent software creators to monetize any software they choose to sell — fully open source, free/paid versions, or fully closed source. The licensing layer is agnostic to your decision.
|
|
</p>
|
|
<div class="cta-row">
|
|
<a class="btn primary lg" href="#install">Install Keysat <span class="arrow">→</span></a>
|
|
<a class="btn secondary lg" href="#how">See how it works</a>
|
|
</div>
|
|
<div class="trust">
|
|
<span><i data-lucide="server" style="width:14px;height:14px"></i> Runs on Start9</span>
|
|
<span class="dot"></span>
|
|
<span><i data-lucide="bitcoin" style="width:14px;height:14px"></i> Pays via BTCPay</span>
|
|
<span class="dot"></span>
|
|
<span><i data-lucide="wifi-off" style="width:14px;height:14px"></i> Verifies offline</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="cert" role="img" aria-label="Sample license certificate">
|
|
<div class="seal">₿</div>
|
|
<div class="stamp">— Certificate of License —</div>
|
|
<h4>Sample Product</h4>
|
|
<div class="sub">Issued under default policy · single seat · 1 year</div>
|
|
<div class="field">License key</div>
|
|
<div class="value">KS-9F2A-7C41-XK22-6D8E</div>
|
|
<div class="row">
|
|
<div>
|
|
<div class="field">Issued</div>
|
|
<div class="value" style="font-size:13px">2026-04-22</div>
|
|
</div>
|
|
<div>
|
|
<div class="field">Expires</div>
|
|
<div class="value" style="font-size:13px">2027-04-22</div>
|
|
</div>
|
|
</div>
|
|
<div class="sig">Ed25519 · mz7q8r4t1v…h3k2pXq9wL · ✓ verified offline</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block tinted" id="why">
|
|
<div class="wrap">
|
|
<div class="section-head">
|
|
<span class="eyebrow">What this enables</span>
|
|
<h2>A complete sell-your-software stack, sovereign end-to-end.</h2>
|
|
<p>Keysat is the licensing layer. BTCPay handles payments. Your hardware holds the keys. No third party can mint, revoke, or read your sales records.</p>
|
|
</div>
|
|
<div class="value-grid">
|
|
<div class="item">
|
|
<div class="icon-wrap"><i data-lucide="zap"></i></div>
|
|
<h3>Bitcoin payments, your store</h3><div class="accent-bar"></div>
|
|
<p>BTCPay Server on your own Start9 takes the payment. Lightning settles in seconds. Funds land in your wallet — no intermediary holds them.</p>
|
|
</div>
|
|
<div class="item">
|
|
<div class="icon-wrap"><i data-lucide="key-round"></i></div>
|
|
<h3>You own the signing key</h3><div class="accent-bar"></div>
|
|
<p>The Ed25519 keypair lives on your hardware. Every license is signed by it. There's no third party who could mint or revoke licenses.</p>
|
|
</div>
|
|
<div class="item">
|
|
<div class="icon-wrap"><i data-lucide="wifi-off"></i></div>
|
|
<h3>Offline verification</h3><div class="accent-bar"></div>
|
|
<p>Your software verifies licenses against an embedded public key. No network call. Customer apps work even if your Keysat goes offline.</p>
|
|
</div>
|
|
<div class="item">
|
|
<div class="icon-wrap"><i data-lucide="ticket"></i></div>
|
|
<h3>Sell however you want</h3><div class="accent-bar"></div>
|
|
<p>One-time purchases for the whole app. Free / paid splits. Trials. Recurring renewals. Time-limited licenses, multi-seat licenses, comp keys for press. The licensing layer is a primitive — you decide the business model.</p>
|
|
</div>
|
|
<div class="item">
|
|
<div class="icon-wrap"><i data-lucide="tag"></i></div>
|
|
<h3>Discount & comp codes</h3><div class="accent-bar"></div>
|
|
<p>Percent-off, fixed-sats-off, or free-license codes (no payment required). Run launch promos, comp keys for press, track partner campaigns.</p>
|
|
</div>
|
|
<div class="item">
|
|
<div class="icon-wrap"><i data-lucide="wrench"></i></div>
|
|
<h3>SDKs in your language</h3><div class="accent-bar"></div>
|
|
<p>Rust, TypeScript, Python — wire-compatible offline verifiers. Five lines of code in your app and you're verifying real signatures.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block case-section" id="creators">
|
|
<div class="wrap">
|
|
<div class="section-head">
|
|
<span class="eyebrow">Real creators, real software</span>
|
|
<h2>Built by experts in their craft, not coders.</h2>
|
|
<p>Empowering the next generation of software creators. The people who actually know the work — accountants, trainers, teachers, builders — can finally ship the tool they’ve always wanted, because AI handed them the keyboard. Keysat is the licensing layer that lets them get paid for what they made.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="case-slider" id="case-slider" aria-label="Independent creators using Keysat">
|
|
<div class="case-track" id="case-track">
|
|
|
|
<!-- ===== Slide 1: Tax accountant ===== -->
|
|
<article class="case-slide" data-slide="0">
|
|
<div class="photo">
|
|
<img src="assets/case-marisol.jpg" alt="Marisol Vargas, solo CPA" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
|
|
<div class="photo-fallback" style="display:none">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 22a8 8 0 0116 0"/></svg>
|
|
<div class="label">Photo placeholder</div>
|
|
<div>Save a photoreal portrait at:</div>
|
|
<div class="filename">assets/case-marisol.jpg</div>
|
|
</div>
|
|
</div>
|
|
<div class="body">
|
|
<div class="eyebrow-tag">Solo CPA</div>
|
|
<h3 class="name">Marisol Vargas</h3>
|
|
<p class="role">12 years specializing in small-business tax. Built her own software because the existing tools didn’t fit her workflow.</p>
|
|
<div class="product-block">
|
|
<svg class="product-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="2" width="16" height="20" rx="2"/><line x1="8" y1="6" x2="16" y2="6"/><line x1="8" y1="10" x2="16" y2="10"/><line x1="8" y1="14" x2="12" y2="14"/></svg>
|
|
<div>
|
|
<div class="product-name">SchedulCalc</div>
|
|
<p class="product-tag">Schedule C + 1099 reconciler for solo accountants. Replaces a $1,200/yr software stack with one focused tool.</p>
|
|
</div>
|
|
</div>
|
|
<blockquote>“I worked with bloated tax software for twelve years. With AI I built one that fits how I actually think — in three months, on weekends.”</blockquote>
|
|
<div class="stats">
|
|
<div><span class="stat-num">42</span>active licenses</div>
|
|
<div><span class="stat-num">$99/yr</span>per seat</div>
|
|
<div><span class="stat-num">8 mo.</span>since launch</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<!-- ===== Slide 2: Powerlifting coach ===== -->
|
|
<article class="case-slide" data-slide="1">
|
|
<div class="photo">
|
|
<img src="assets/case-tomas.jpg" alt="Tomas Kovac, powerlifting coach" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
|
|
<div class="photo-fallback" style="display:none">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 22a8 8 0 0116 0"/></svg>
|
|
<div class="label">Photo placeholder</div>
|
|
<div>Save a photoreal portrait at:</div>
|
|
<div class="filename">assets/case-tomas.jpg</div>
|
|
</div>
|
|
</div>
|
|
<div class="body">
|
|
<div class="eyebrow-tag">Powerlifting coach</div>
|
|
<h3 class="name">Tomas Kovac</h3>
|
|
<p class="role">12 years in the gym. Built RPE-based programming software because off-the-shelf apps assume gym-membership-app generic.</p>
|
|
<div class="product-block">
|
|
<svg class="product-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" y1="6" x2="6" y2="18"/><line x1="18" y1="6" x2="18" y2="18"/><line x1="6" y1="12" x2="18" y2="12"/><circle cx="6" cy="9" r="1.5"/><circle cx="6" cy="15" r="1.5"/><circle cx="18" cy="9" r="1.5"/><circle cx="18" cy="15" r="1.5"/></svg>
|
|
<div>
|
|
<div class="product-name">BarbellTracker</div>
|
|
<p class="product-tag">RPE-based programming and autoregulation for one-on-one coaches. Built around how strength athletes actually train.</p>
|
|
</div>
|
|
</div>
|
|
<blockquote>“I knew exactly what coaches needed because I was the coach. AI handled the engineering — I handled the design.”</blockquote>
|
|
<div class="stats">
|
|
<div><span class="stat-num">87</span>active coaches</div>
|
|
<div><span class="stat-num">20k sats/mo</span>per seat</div>
|
|
<div><span class="stat-num">14 mo.</span>since launch</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<!-- ===== Slide 3: Homeschooling parent ===== -->
|
|
<article class="case-slide" data-slide="2">
|
|
<div class="photo">
|
|
<img src="assets/case-hana.jpg" alt="Hana Brennan, homeschooling parent" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
|
|
<div class="photo-fallback" style="display:none">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 22a8 8 0 0116 0"/></svg>
|
|
<div class="label">Photo placeholder</div>
|
|
<div>Save a photoreal portrait at:</div>
|
|
<div class="filename">assets/case-hana.jpg</div>
|
|
</div>
|
|
</div>
|
|
<div class="body">
|
|
<div class="eyebrow-tag">Homeschooling mom</div>
|
|
<h3 class="name">Hana Brennan</h3>
|
|
<p class="role">Three kids, three different curriculum tracks. Built her own week-planner because every existing tool assumed one student.</p>
|
|
<div class="product-block">
|
|
<svg class="product-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 4h7a3 3 0 013 3v13a2 2 0 00-2-2H2zM22 4h-7a3 3 0 00-3 3v13a2 2 0 012-2h8z"/></svg>
|
|
<div>
|
|
<div class="product-name">SeasonsOfLearning</div>
|
|
<p class="product-tag">Multi-grade week planner for homeschool families with kids on different tracks. Mixes curricula across ages.</p>
|
|
</div>
|
|
</div>
|
|
<blockquote>“I sketched the workflow on a notepad in October. By January my kids’ school days were running on it. Now 200 other families use it too.”</blockquote>
|
|
<div class="stats">
|
|
<div><span class="stat-num">208</span>families</div>
|
|
<div><span class="stat-num">$48/yr</span>per family</div>
|
|
<div><span class="stat-num">11 mo.</span>since launch</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div class="wrap">
|
|
<div class="case-controls" id="case-controls" role="tablist" aria-label="Case study navigation">
|
|
<button class="case-dot active" data-target="0" aria-label="Show case 1"></button>
|
|
<button class="case-dot" data-target="1" aria-label="Show case 2"></button>
|
|
<button class="case-dot" data-target="2" aria-label="Show case 3"></button>
|
|
</div>
|
|
<div class="footnote">Illustrative examples of the kinds of creators Keysat is built for. Real Keysat creators — come be one of them.</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block" id="how">
|
|
<div class="wrap">
|
|
<div class="section-head">
|
|
<span class="eyebrow">How it works</span>
|
|
<h2>Five steps, end to end.</h2>
|
|
<p>From install to first sale in an afternoon. No cloud account to create, no API keys to copy.</p>
|
|
</div>
|
|
<ol class="flow">
|
|
<li class="step"><div class="num">01</div><h3>Install on your Start9</h3><p>One click from <code>registry.keysat.xyz</code> in the StartOS marketplace. BTCPay comes bundled as a dependency. (Sideload the <code>.s9pk</code> directly if you prefer.)</p></li>
|
|
<li class="step"><div class="num">02</div><h3>Connect BTCPay</h3><p>One click in the StartOS Actions tab. Authorize once on BTCPay's consent page; Keysat registers a webhook automatically.</p></li>
|
|
<li class="step"><div class="num">03</div><h3>Define products + policies</h3><p>Declare a product, set its price in sats, define a policy (duration, seat cap, trial, entitlements).</p></li>
|
|
<li class="step"><div class="num">04</div><h3>Embed your public key</h3><p>Copy your Keysat public key into your app. Add the SDK. Five lines of code verifies a signature at startup.</p></li>
|
|
<li class="step"><div class="num">05</div><h3>Share your purchase URL</h3><p>Buyers hit your public URL, pay in Bitcoin, get a signed license. Their copy of your software boots up licensed.</p></li>
|
|
</ol>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block tinted" id="integrate">
|
|
<div class="wrap">
|
|
<div class="code-section">
|
|
<div class="pitch">
|
|
<span class="eyebrow" style="color:var(--gold-700); font-size:11.5px; font-weight:700; letter-spacing:0.18em; text-transform:uppercase;">For developers and AI agents</span>
|
|
<h3>Five lines, in the language you or your AI agents already write.</h3>
|
|
<p>Keysat licenses are Ed25519-signed and Crockford base32-encoded. Verification is pure-function — no network, no daemon, no shared state. Hand the docs to your coding agent and tell it to wire licensing into your software; the integration is small enough to fit in one prompt.</p>
|
|
<ul>
|
|
<li>Wire-compatible across SDKs (TypeScript, Rust, Python)</li>
|
|
<li>Public key embedded at compile time</li>
|
|
<li>Returns product, policy, expiry, entitlements</li>
|
|
<li>Source-available — agents can read the verifier source directly</li>
|
|
</ul>
|
|
</div>
|
|
<div class="code-card">
|
|
<div class="code-tabs">
|
|
<button class="active" data-lang="ts">TypeScript</button>
|
|
<button data-lang="rs">Rust</button>
|
|
<button data-lang="py">Python</button>
|
|
<span class="install" id="install-cmd">npm install @keysat/licensing-client</span>
|
|
</div>
|
|
<pre class="code" id="code-ts"><span class="k">import</span> { <span class="f">Verifier</span>, <span class="f">PublicKey</span> } <span class="k">from</span> <span class="s">'@keysat/licensing-client'</span>
|
|
|
|
<span class="k">const</span> verifier = <span class="k">new</span> <span class="f">Verifier</span>(
|
|
<span class="f">PublicKey</span>.<span class="f">fromPem</span>(ISSUER_PEM)
|
|
)
|
|
|
|
<span class="k">const</span> ok = verifier.<span class="f">verify</span>(licenseKeyFromUser)
|
|
console.<span class="f">log</span>(<span class="s">'licensed:'</span>, ok.productId, ok.expires)</pre>
|
|
<pre class="code" id="code-rs" style="display:none"><span class="c">// Cargo.toml</span>
|
|
<span class="c">// licensing-client = "0.1"</span>
|
|
|
|
<span class="k">use</span> licensing_client::{<span class="f">Verifier</span>, <span class="f">PublicKeyPem</span>};
|
|
|
|
<span class="k">let</span> pk = <span class="f">PublicKeyPem</span>::from_str(ISSUER_PEM)<span class="p">?</span>;
|
|
<span class="k">let</span> verifier = <span class="f">Verifier</span>::new(pk);
|
|
<span class="k">let</span> ok = verifier.verify(&license_key)<span class="p">?</span>;
|
|
println!(<span class="s">"licensed: {}"</span>, ok.product_id);</pre>
|
|
<pre class="code" id="code-py" style="display:none"><span class="k">from</span> keysat_licensing_client <span class="k">import</span> Verifier, PublicKey
|
|
|
|
verifier = <span class="f">Verifier</span>(<span class="f">PublicKey</span>.<span class="f">from_pem</span>(ISSUER_PEM))
|
|
ok = verifier.<span class="f">verify</span>(license_key_from_user)
|
|
|
|
<span class="k">print</span>(<span class="s">"licensed for"</span>, ok.product_id)</pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block" id="sovereign">
|
|
<div class="wrap">
|
|
<div class="section-head">
|
|
<span class="eyebrow">Sovereign by default</span>
|
|
<h2>Everything stays on your hardware.</h2>
|
|
<p>Migrate Start9 boxes — Keysat goes with you. If the Keysat project disappears tomorrow, your already-issued licenses keep verifying: the public key is embedded in your software, the private key is on your machine.</p>
|
|
</div>
|
|
<div class="sov">
|
|
<div class="panel">
|
|
<h3>What you keep</h3>
|
|
<div class="sub">On your Start9, in your normal backups.</div>
|
|
<ul>
|
|
<li>Signing keypair</li>
|
|
<li>Customer email · npub list</li>
|
|
<li>Sale records</li>
|
|
<li>Audit log</li>
|
|
<li>BTCPay invoice history</li>
|
|
<li>Webhook subscribers</li>
|
|
<li>Bitcoin (your wallet)</li>
|
|
</ul>
|
|
<p class="footnote">Backed up automatically by StartOS as part of your normal backup routine.</p>
|
|
</div>
|
|
<div class="panel dark">
|
|
<h3>Or accept fiat, on your terms</h3>
|
|
<div class="sub">Coming soon: opt-in card payments via Zaprite.</div>
|
|
<p style="font-size:14px; line-height:1.55; color:rgba(245,241,232,0.85); margin:0 0 16px;">If your customers prefer paying with credit cards over Bitcoin, you’ll be able to plug Zaprite into Keysat as an alternative payment provider. Same Keysat license-issuance flow, but the payment can come through Stripe-via-Zaprite for cards or any of Zaprite’s Bitcoin rails (BTCPay, Strike, Unchained). Trades off some sovereignty — cards mean Stripe KYC and customer PII flowing through Zaprite — in exchange for a much wider addressable audience.</p>
|
|
<p style="font-size:14px; line-height:1.55; color:rgba(245,241,232,0.85); margin:0 0 16px;">Keysat stays sovereign-by-default. Card payments are something you opt into per Keysat install if your business needs them. Shipping in v0.3.</p>
|
|
<p class="footnote">Source-available license · pay your operator-style trade-offs deliberately, never by default.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block tinted" id="install">
|
|
<div class="wrap">
|
|
<div class="section-head">
|
|
<span class="eyebrow">Install</span>
|
|
<h2>From the marketplace, or sideload directly.</h2>
|
|
<p>Either path leaves you in the same place: a running Keysat on your Start9, ready to connect BTCPay.</p>
|
|
</div>
|
|
<div class="install-grid">
|
|
<div class="install-card featured">
|
|
<span class="cap">Recommended</span>
|
|
<h3>From the marketplace</h3>
|
|
<p>Add the Keysat marketplace to your Start9, then click Install.</p>
|
|
<div class="cmd-card">
|
|
<span>https://registry.keysat.xyz</span>
|
|
<button class="copy" data-copy="https://registry.keysat.xyz">Copy</button>
|
|
</div>
|
|
<p style="margin-top:16px; font-size:13.5px; color:var(--ink-500)">StartOS dashboard → Marketplace → Add → paste the URL.</p>
|
|
<p style="margin-top:14px; font-size:13.5px; color:var(--ink-700)"><strong>Then activate your license:</strong></p>
|
|
<a href="https://licensing.keysat.xyz/buy/keysat" class="btn primary" style="display:inline-flex; margin-top:8px; width:100%; justify-content:center;">Buy a license →</a>
|
|
</div>
|
|
<div class="install-card">
|
|
<span class="cap">Alternative</span>
|
|
<h3>Sideload</h3>
|
|
<p>If you'd rather not add the marketplace:</p>
|
|
<ol>
|
|
<li>Download <code>keysat_x86_64.s9pk</code> from <a href="https://github.com/keysat-xyz/keysat/releases">GitHub releases</a>.</li>
|
|
<li>StartOS dashboard → Sideload → drag the file in.</li>
|
|
<li>Click Install.</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="block" id="faq">
|
|
<div class="wrap">
|
|
<div class="section-head">
|
|
<span class="eyebrow">Common questions</span>
|
|
<h2>What people ask.</h2>
|
|
</div>
|
|
<div class="faq">
|
|
<div>
|
|
<h3>What happens if Keysat the project disappears?</h3>
|
|
<p>Your software keeps working. The public key is embedded in your app at compile time, and offline verification doesn't depend on us. The wire format is documented; you can reimplement the verifier in any language in an afternoon.</p>
|
|
</div>
|
|
<div>
|
|
<h3>Can I do free or comped licenses?</h3>
|
|
<p>Yes. Define a discount code with type <code>free_license</code> and the buyer redeems it at checkout without paying. Useful for press, beta testers, partners, and giveaways.</p>
|
|
</div>
|
|
<div>
|
|
<h3>What about subscriptions?</h3>
|
|
<p>v0.1 issues fixed-duration licenses (e.g. 1 year) with offline expiry. True recurring billing — auto-renew without buyer interaction — lands in v0.3 alongside license-tier upgrades, volume packs, and Zaprite card payments.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<footer class="site">
|
|
<div class="wrap">
|
|
<div class="top">
|
|
<div class="brand-block">
|
|
<div class="brand"><img src="assets/keysat-mark.svg" alt=""><span>Keysat</span></div>
|
|
<p class="tag">Software licensing for independent creators. Self-hosted, sovereign, source-available.</p>
|
|
</div>
|
|
<div class="col">
|
|
<h5>Product</h5>
|
|
<a href="#why">Why Keysat</a>
|
|
<a href="#how">How it works</a>
|
|
<a href="#install">Install</a>
|
|
<a href="https://registry.keysat.xyz">Marketplace</a>
|
|
</div>
|
|
<div class="col">
|
|
<h5>Developers</h5>
|
|
<a href="#integrate">Integration</a>
|
|
<a href="https://docs.keysat.xyz">SDKs</a>
|
|
<a href="https://docs.keysat.xyz/wire-format">Wire format</a>
|
|
<a href="https://github.com/keysat-xyz">GitHub</a>
|
|
</div>
|
|
<div class="col">
|
|
<h5>Contact</h5>
|
|
<a href="mailto:licensing@keysat.xyz">licensing@keysat.xyz</a>
|
|
<a href="https://docs.keysat.xyz/changelog">Changelog</a>
|
|
<a href="https://github.com/keysat-xyz/keysat/issues">Issues</a>
|
|
</div>
|
|
</div>
|
|
<div class="bottom">
|
|
<span>© Keysat. Source-available; not open-source.</span>
|
|
<span>Runs on Start9 · Pays via BTCPay · Verifies offline</span>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<script src="https://unpkg.com/lucide@latest"></script>
|
|
<script>
|
|
lucide.createIcons();
|
|
|
|
// Tab switching for code samples
|
|
const installCmds = {
|
|
ts: 'npm install @keysat/licensing-client',
|
|
rs: 'cargo add licensing-client',
|
|
py: 'pip install keysat-licensing-client',
|
|
};
|
|
document.querySelectorAll('.code-tabs button').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const lang = btn.dataset.lang;
|
|
document.querySelectorAll('.code-tabs button').forEach(b => b.classList.toggle('active', b === btn));
|
|
['ts','rs','py'].forEach(l => {
|
|
document.getElementById('code-' + l).style.display = l === lang ? 'block' : 'none';
|
|
});
|
|
document.getElementById('install-cmd').textContent = installCmds[lang];
|
|
});
|
|
});
|
|
|
|
// Copy buttons
|
|
document.querySelectorAll('.copy[data-copy]').forEach(btn => {
|
|
btn.addEventListener('click', async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(btn.dataset.copy);
|
|
const original = btn.textContent;
|
|
btn.textContent = 'Copied';
|
|
setTimeout(() => { btn.textContent = original; }, 1400);
|
|
} catch (e) {}
|
|
});
|
|
});
|
|
|
|
// Case-study slider — auto-advance with pause on hover, dot indicators
|
|
(function() {
|
|
const track = document.getElementById('case-track');
|
|
const slider = document.getElementById('case-slider');
|
|
const dots = document.querySelectorAll('.case-dot');
|
|
if (!track || !slider) return;
|
|
|
|
const slides = track.querySelectorAll('.case-slide');
|
|
const SLIDE_COUNT = slides.length;
|
|
const ADVANCE_MS = 9000; // ~9s per slide — long enough to read
|
|
let current = 0;
|
|
let timer = null;
|
|
|
|
function go(i) {
|
|
current = ((i % SLIDE_COUNT) + SLIDE_COUNT) % SLIDE_COUNT;
|
|
track.style.transform = 'translateX(-' + (current * 100) + '%)';
|
|
dots.forEach((d, di) => d.classList.toggle('active', di === current));
|
|
}
|
|
function next() { go(current + 1); }
|
|
|
|
function start() {
|
|
if (timer) clearInterval(timer);
|
|
timer = setInterval(next, ADVANCE_MS);
|
|
}
|
|
function stop() {
|
|
if (timer) clearInterval(timer);
|
|
timer = null;
|
|
}
|
|
|
|
// Pause on hover; resume on leave.
|
|
slider.addEventListener('mouseenter', stop);
|
|
slider.addEventListener('mouseleave', start);
|
|
// Also pause when the tab isn't visible — saves CPU.
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.hidden) stop(); else start();
|
|
});
|
|
|
|
// Manual nav via dots: jump and reset the timer.
|
|
dots.forEach(dot => {
|
|
dot.addEventListener('click', () => {
|
|
const t = parseInt(dot.dataset.target, 10) || 0;
|
|
go(t);
|
|
start();
|
|
});
|
|
});
|
|
|
|
start();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|