Add integrated checkout, child safety section, and content polish

- checkout.el: Custom Stripe Payment Element page at /checkout?plan=...
- safety.el: Hard Bell and emergency routing architecture section
- main.el: Wire checkout + safety, /api/payment-intent, STRIPE_PUBLISHABLE_KEY
- enterprise_terms.el: Add nav bar (was missing, page had no navigation)
- styles.el: Checkout buttons now link to integrated page, not hosted Stripe
- El runtime: Auto-detect HTML responses, serve text/html vs application/json
- footer.el: Wordmark image centered above "Built Different." tagline
- environmental.el: Replace SQLite with custom on-device storage
- enterprise.el: Replace SQLite with custom on-device storage
- pricing.el: Local models degraded performance note near Ollama feature
- about.el: "left home at fifteen", remove programming language mention
This commit is contained in:
Will Anderson
2026-04-29 16:59:57 -05:00
parent d190e08f38
commit 393d982d04
10 changed files with 567 additions and 29 deletions
+427
View File
@@ -0,0 +1,427 @@
// checkout.el Integrated Stripe checkout page.
//
// Uses Stripe Payment Element (not hosted checkout) so the entire
// purchase experience lives on neurontechnologies.ai. The page is
// designed to match the Neuron brand navy, clean, no Stripe chrome.
//
// Flow:
// 1. GET /checkout?plan=founding|professional
// 2. Page JS calls POST /api/payment-intent { client_secret, publishable_key, plan }
// 3. Stripe Payment Element mounts into #payment-element
// 4. User fills name, email, card submits
// 5. stripe.confirmPayment() redirects to /marketplace/success
fn checkout_page(plan: String, pub_key: String) -> String {
let is_founding: Bool = str_eq(plan, "founding")
let plan_name: String = if is_founding { "Founding Member" } else { "Professional" }
let plan_price: String = if is_founding { "$199" } else { "$19 / month" }
let plan_desc: String = if is_founding {
"Pay once. Neuron inference forever. No subscription, ever."
} else {
"Full access. Neuron inference — cheaper than what you're paying now."
}
let plan_cadence: String = if is_founding { "one-time" } else { "billed monthly" }
let features_html: String = if is_founding {
"<li>Neuron inference &#8212; priced below competitors, forever</li>
<li>Everything in Professional &#8212; forever</li>
<li>Never pay again &#8212; lifetime updates included</li>
<li>Founding member badge in the app</li>
<li>Private community &#8212; direct line to the team</li>
<li>Shape the roadmap &#8212; your votes carry more weight</li>
<li>Beta features before general release</li>
<li>Name in the credits</li>"
} else {
"<li>Neuron inference &#8212; metered, priced below OpenAI and Anthropic</li>
<li>Persistent memory &#8212; never resets</li>
<li>Unlimited projects</li>
<li>Full plugin marketplace</li>
<li>IDE, Slack, and more integrations</li>
<li>Early access to new features</li>"
}
return "
<nav id=\"nav\">
<div class=\"nav-inner\">
<a href=\"/\" class=\"nav-logo\" aria-label=\"Neuron home\"><img src=\"/assets/brand/neuron-wordmark-on-light.png\" srcset=\"/assets/brand/neuron-wordmark-on-light@2x.png 2x\" alt=\"Neuron\" height=\"28\"></a>
<div class=\"nav-links\">
<a href=\"/\" class=\"nav-link\">&#8592; Back</a>
</div>
</div>
</nav>
<main style=\"min-height: 100vh; padding: clamp(6rem, 14vh, 9rem) 2rem 4rem;\">
<div class=\"checkout-shell\">
<!-- Left: order summary -->
<div class=\"checkout-summary\">
<p class=\"label\" style=\"margin-bottom: 1.5rem; color: var(--navy);\">Your order</p>
<div style=\"margin-bottom: 2rem;\">
<p class=\"checkout-plan-name\">" + plan_name + "</p>
<p class=\"checkout-plan-desc\">" + plan_desc + "</p>
<div style=\"display: flex; align-items: baseline; gap: .5rem; margin-top: 1.25rem;\">
<span class=\"checkout-price\">" + plan_price + "</span>
<span class=\"checkout-cadence\">" + plan_cadence + "</span>
</div>
</div>
<div class=\"navy-line-left\" style=\"width: 3rem; margin-bottom: 1.75rem;\"></div>
<ul class=\"checkout-features\">
" + features_html + "
</ul>
<p class=\"checkout-guarantee\">
Your data stays yours. Runs locally. No telemetry.
</p>
</div>
<!-- Right: payment form -->
<div class=\"checkout-form-wrap\">
<p class=\"label\" style=\"margin-bottom: 1.75rem;\">Payment</p>
<form id=\"payment-form\" autocomplete=\"on\">
<div class=\"checkout-field-group\">
<div class=\"checkout-field\">
<label for=\"buyer-name\" class=\"checkout-label\">Full name</label>
<input id=\"buyer-name\" name=\"name\" type=\"text\" autocomplete=\"name\"
class=\"checkout-input\" placeholder=\"Will Anderson\" required>
</div>
<div class=\"checkout-field\">
<label for=\"buyer-email\" class=\"checkout-label\">Email</label>
<input id=\"buyer-email\" name=\"email\" type=\"email\" autocomplete=\"email\"
class=\"checkout-input\" placeholder=\"you@example.com\" required>
</div>
</div>
<div class=\"checkout-payment-element-wrap\">
<div id=\"payment-element\">
<!-- Stripe Payment Element mounts here -->
<div class=\"checkout-element-loading\">Loading payment form&#8230;</div>
</div>
</div>
<div id=\"payment-message\" class=\"checkout-message\" style=\"display:none;\"></div>
<button id=\"submit-btn\" class=\"checkout-submit\" type=\"submit\" disabled>
<span id=\"submit-label\">Complete purchase &#8594;</span>
<span id=\"submit-spinner\" style=\"display:none;\">Processing&#8230;</span>
</button>
<p class=\"checkout-security\">
<svg aria-hidden=\"true\" width=\"12\" height=\"14\" viewBox=\"0 0 12 14\" fill=\"none\">
<path d=\"M6 0L0 2.5V7c0 3.3 2.5 6.3 6 7 3.5-.7 6-3.7 6-7V2.5L6 0z\" fill=\"currentColor\" opacity=\".35\"/>
<path d=\"M4 7l1.5 1.5L8.5 5\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>
</svg>
Secured by Stripe &nbsp;&middot;&nbsp; 256-bit TLS &nbsp;&middot;&nbsp; PCI DSS compliant
</p>
</form>
</div>
</div>
</main>
<!-- Stripe.js -->
<script src=\"https://js.stripe.com/v3/\" async></script>
<style>
.checkout-shell {
max-width: 960px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 5rem;
align-items: start;
}
@media (max-width: 720px) {
.checkout-shell { grid-template-columns: 1fr; gap: 3rem; }
}
.checkout-plan-name {
font-family: var(--head);
font-size: clamp(1.5rem, 3vw, 2rem);
font-weight: 600;
color: var(--t1);
letter-spacing: -0.02em;
margin: 0 0 .5rem;
}
.checkout-plan-desc {
font-family: var(--body);
font-weight: 300;
font-size: .9375rem;
color: var(--t2);
line-height: 1.65;
margin: 0;
}
.checkout-price {
font-family: var(--head);
font-size: 2.5rem;
font-weight: 700;
color: var(--t1);
letter-spacing: -0.03em;
line-height: 1;
}
.checkout-cadence {
font-family: var(--body);
font-size: .8125rem;
color: var(--t3);
letter-spacing: .04em;
}
.checkout-features {
list-style: none;
padding: 0;
margin: 0 0 2rem;
display: flex;
flex-direction: column;
gap: .6rem;
}
.checkout-features li {
font-family: var(--body);
font-weight: 300;
font-size: .9rem;
color: var(--t2);
padding-left: 1.1rem;
position: relative;
}
.checkout-features li::before {
content: '';
position: absolute;
left: 0;
color: var(--navy);
opacity: .6;
}
.checkout-guarantee {
font-family: var(--body);
font-weight: 300;
font-size: .8125rem;
color: var(--t3);
line-height: 1.6;
margin: 0;
}
.checkout-field-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1.5rem;
}
@media (max-width: 480px) { .checkout-field-group { grid-template-columns: 1fr; } }
.checkout-field { display: flex; flex-direction: column; gap: .4rem; }
.checkout-label {
font-family: var(--body);
font-size: .75rem;
font-weight: 500;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--t2);
}
.checkout-input {
font-family: var(--body);
font-size: .9375rem;
font-weight: 300;
color: var(--t1);
background: #fff;
border: 1px solid rgba(0,82,160,.22);
padding: .75rem 1rem;
outline: none;
transition: border-color .2s;
border-radius: 0;
-webkit-appearance: none;
appearance: none;
}
.checkout-input::placeholder { color: var(--t3); }
.checkout-input:focus { border-color: rgba(0,82,160,.6); box-shadow: 0 0 0 3px rgba(0,82,160,.08); }
.checkout-payment-element-wrap {
margin-bottom: 1.5rem;
border: 1px solid rgba(0,82,160,.22);
padding: 1.25rem;
background: #fff;
min-height: 80px;
}
.checkout-element-loading {
font-family: var(--body);
font-size: .875rem;
color: var(--t3);
}
.checkout-message {
font-family: var(--body);
font-size: .875rem;
color: #c0392b;
margin-bottom: 1rem;
padding: .75rem 1rem;
background: rgba(192,57,43,.06);
border-left: 2px solid rgba(192,57,43,.4);
}
.checkout-submit {
width: 100%;
padding: 1.05rem 2rem;
background: var(--navy);
color: #fff;
font-family: var(--body);
font-size: .8125rem;
font-weight: 600;
letter-spacing: .12em;
text-transform: uppercase;
border: none;
cursor: pointer;
transition: background .2s, opacity .2s;
margin-bottom: 1.25rem;
}
.checkout-submit:hover:not(:disabled) { background: #0078D4; }
.checkout-submit:disabled { opacity: .5; cursor: not-allowed; }
.checkout-security {
font-family: var(--body);
font-size: .75rem;
color: var(--t3);
display: flex;
align-items: center;
gap: .4rem;
margin: 0;
}
</style>
<script>
(function() {
var PLAN = '" + plan + "';
var STRIPE_PK = '" + pub_key + "';
var stripe, elements;
// Wait for Stripe.js to load
function waitForStripe(cb) {
if (window.Stripe) { cb(); return; }
setTimeout(function() { waitForStripe(cb); }, 50);
}
function showMessage(msg) {
var el = document.getElementById('payment-message');
el.textContent = msg;
el.style.display = 'block';
}
function setLoading(loading) {
var btn = document.getElementById('submit-btn');
var label = document.getElementById('submit-label');
var spinner = document.getElementById('submit-spinner');
btn.disabled = loading;
label.style.display = loading ? 'none' : '';
spinner.style.display = loading ? '' : 'none';
}
// Fetch client secret from our server
fetch('/api/payment-intent', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ plan: PLAN })
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (!data.client_secret) {
showMessage('Unable to initialise payment. Please try again.');
return;
}
waitForStripe(function() {
stripe = Stripe(STRIPE_PK);
elements = stripe.elements({
clientSecret: data.client_secret,
appearance: {
theme: 'flat',
variables: {
colorPrimary: '#0052A0',
colorBackground: '#ffffff',
colorText: '#1A1A2E',
colorDanger: '#c0392b',
colorTextPlaceholder:'#9B9BAD',
borderRadius: '0px',
fontFamily: 'system-ui, -apple-system, sans-serif',
fontSizeBase: '15px',
fontWeightNormal: '300',
spacingUnit: '4px',
},
rules: {
'.Input': {
border: '1px solid rgba(0,82,160,.22)',
boxShadow: 'none',
padding: '10px 14px',
},
'.Input:focus': {
border: '1px solid rgba(0,82,160,.6)',
boxShadow: '0 0 0 3px rgba(0,82,160,.08)',
outline: 'none',
},
'.Label': {
fontSize: '11px',
fontWeight: '500',
letterSpacing: '.06em',
textTransform: 'uppercase',
color: '#6B6B7E',
marginBottom: '6px',
},
'.Tab': {
border: '1px solid rgba(0,82,160,.18)',
boxShadow: 'none',
},
'.Tab--selected': {
border: '1px solid rgba(0,82,160,.5)',
boxShadow: '0 0 0 2px rgba(0,82,160,.12)',
},
'.Error': { color: '#c0392b' },
}
}
});
var paymentEl = elements.create('payment', {
fields: { billingDetails: { name: 'never', email: 'never' } }
});
paymentEl.mount('#payment-element');
paymentEl.on('ready', function() {
document.querySelector('.checkout-element-loading') &&
document.querySelector('.checkout-element-loading').remove();
document.getElementById('submit-btn').disabled = false;
});
});
})
.catch(function() {
showMessage('Unable to connect. Please check your connection and try again.');
});
// Submit
document.getElementById('payment-form').addEventListener('submit', async function(e) {
e.preventDefault();
if (!stripe || !elements) return;
var name = document.getElementById('buyer-name').value.trim();
var email = document.getElementById('buyer-email').value.trim();
if (!name || !email) {
showMessage('Please enter your name and email.');
return;
}
setLoading(true);
document.getElementById('payment-message').style.display = 'none';
var result = await stripe.confirmPayment({
elements: elements,
confirmParams: {
return_url: window.location.origin + '/marketplace/success',
payment_method_data: {
billing_details: { name: name, email: email }
},
receipt_email: email,
}
});
if (result.error) {
showMessage(result.error.message || 'Payment failed. Please try again.');
setLoading(false);
}
// On success, Stripe redirects to return_url automatically.
});
})();
</script>
"
}