Compare commits

..

7 Commits

Author SHA1 Message Date
will.anderson da5d498de5 feat(web): add downloads page and wire account download card
The funnel dead-ended at "we'll email you" — there was no downloads
surface. Add a real /downloads page in the landing template style
(shared nav + footer + page shell) with client-side navigator.platform
OS detection. macOS (Apple Silicon .dmg) is featured as the shipping
build; Windows (.msi) and Linux (.deb/.AppImage) are linked but clearly
marked "coming soon" to match current product state — Windows chat and
the Linux soul backend are not yet ready, so presenting them as fully
working would overpromise.

Also un-break the account dashboard download card, which was hardcoded
disabled ("Shipping within 30 days"). It now links the live macOS
installer plus the full /downloads page.
2026-07-14 12:18:11 -05:00
will.anderson b87b0bed24 Merge pull request 'fix(web): soften two unbacked claims for closed-beta honesty' (#157) from fix/honest-claims-closed-beta into main
Deploy marketing to Cloud Run / deploy (push) Failing after 3m33s
2026-06-18 16:40:41 +00:00
Tim Lingo ef352d2b8a fix(web): soften two false claims for closed-beta honesty
Audit found two website claims with no backing implementation:
- '3 marketplace plugins included' (free tier) -> 'Plugin marketplace access
  (coming soon)'. The marketplace is not built; there are no free plugins.
- 'Connectors - day one' -> 'Connectors (rolling out)'. Only a few connectors
  are available; Slack is coming-soon, Gmail/Drive not yet shipped.

String-content only; elc syntax-checks clean. Three other audit flags (no-card
wording, crisis-line copy, post-quantum 'everything encrypted') intentionally
NOT touched - left for human review (sensitive / conflicting evidence).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 00:42:51 -05:00
will.anderson bb690c4690 Merge pull request 'Deploy: clean prod build — strip CGI content' (#112) from stage into main
Deploy marketing to Cloud Run / deploy (push) Failing after 41s
2026-05-11 21:49:47 +00:00
will.anderson 5885826316 Merge pull request 'Deploy: CI fixes (migrations, source guard, asset-only detection)' (#109) from stage into main
Deploy marketing to Cloud Run / deploy (push) Successful in 1m47s
2026-05-11 20:59:04 +00:00
will.anderson cac986c5e1 Merge pull request 'promote: stage → main' (#5) from stage into main
Deploy marketing to Cloud Run / deploy (push) Failing after 30s
2026-05-11 20:31:39 +00:00
will.anderson cd93af38fb Merge pull request 'promote: stage → main' (#5) from stage into main 2026-05-05 11:07:25 +00:00
12 changed files with 229 additions and 56 deletions
+1 -6
View File
@@ -82,12 +82,7 @@ jobs:
echo "Changed files:"
echo "$CHANGED"
NON_ASSET=$(echo "$CHANGED" | grep -v '^src/assets/' | grep -v '^src/shares/' | grep -v '^src/index\.html' | grep -v '^src/about\.html' | grep -v '^src/terms\.html' | grep -v '^src/enterprise-terms\.html' | grep -v '^src/llms\.txt' | grep -v '^migrations/' | grep -v '^scripts/' | grep -v '^tests/' | grep -v '^\.gitea/' | grep -v '^$' || true)
if [ -z "$CHANGED" ] || [ "$CHANGED" = "unknown" ]; then
# No diff (workflow_dispatch with no new commits, or git error).
# Registry may not have a stage-latest base image, so force full build.
echo "asset_only=false" >> "$GITHUB_OUTPUT"
echo "=> No changed files detected (workflow_dispatch?), forcing full build"
elif [ -z "$NON_ASSET" ]; then
if [ -z "$NON_ASSET" ] && [ "$CHANGED" != "unknown" ]; then
echo "asset_only=true" >> "$GITHUB_OUTPUT"
echo "=> Asset-only change detected, will use fast path"
else
-1
View File
@@ -9,7 +9,6 @@
#
# CI pre-build steps (in stage.yaml):
# - neuron-web: built by `elb build` → dist/neuron-landing
# Last rebuilt: 2026-05-11
FROM ubuntu:24.04
+20 -21
View File
@@ -1,4 +1,3 @@
// elhtml_impl.c — El HTML element stubs.
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
@@ -20,11 +19,11 @@ el_val_t el_li(el_val_t attrs, el_val_t children);
el_val_t el_p(el_val_t attrs, el_val_t children);
el_val_t el_span(el_val_t attrs, el_val_t children);
el_val_t el_form(el_val_t attrs, el_val_t children);
el_val_t el_h1(el_val_t attrs, el_val_t children);
el_val_t el_h2(el_val_t attrs, el_val_t children);
el_val_t el_h3(el_val_t attrs, el_val_t children);
el_val_t el_h4(el_val_t attrs, el_val_t children);
el_val_t el_button(el_val_t attrs, el_val_t children);
el_val_t el_h1(el_val_t attrs, el_val_t text);
el_val_t el_h2(el_val_t attrs, el_val_t text);
el_val_t el_h3(el_val_t attrs, el_val_t text);
el_val_t el_h4(el_val_t attrs, el_val_t text);
el_val_t el_button(el_val_t attrs, el_val_t label);
el_val_t el_a(el_val_t href, el_val_t attrs, el_val_t children);
el_val_t el_input(el_val_t type_attr, el_val_t attrs);
el_val_t el_textarea(el_val_t attrs, el_val_t value);
@@ -177,43 +176,43 @@ el_val_t el_form(el_val_t attrs, el_val_t children) {
return 0;
}
el_val_t el_h1(el_val_t attrs, el_val_t children) {
el_val_t el_h1(el_val_t attrs, el_val_t text) {
if (str_eq(attrs, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("<h1>"), children), EL_STR("</h1>"));
return el_str_concat(el_str_concat(EL_STR("<h1>"), el_escape(text)), EL_STR("</h1>"));
}
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h1 "), attrs), EL_STR(">")), children), EL_STR("</h1>"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h1 "), attrs), EL_STR(">")), el_escape(text)), EL_STR("</h1>"));
return 0;
}
el_val_t el_h2(el_val_t attrs, el_val_t children) {
el_val_t el_h2(el_val_t attrs, el_val_t text) {
if (str_eq(attrs, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("<h2>"), children), EL_STR("</h2>"));
return el_str_concat(el_str_concat(EL_STR("<h2>"), el_escape(text)), EL_STR("</h2>"));
}
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h2 "), attrs), EL_STR(">")), children), EL_STR("</h2>"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h2 "), attrs), EL_STR(">")), el_escape(text)), EL_STR("</h2>"));
return 0;
}
el_val_t el_h3(el_val_t attrs, el_val_t children) {
el_val_t el_h3(el_val_t attrs, el_val_t text) {
if (str_eq(attrs, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("<h3>"), children), EL_STR("</h3>"));
return el_str_concat(el_str_concat(EL_STR("<h3>"), el_escape(text)), EL_STR("</h3>"));
}
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h3 "), attrs), EL_STR(">")), children), EL_STR("</h3>"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h3 "), attrs), EL_STR(">")), el_escape(text)), EL_STR("</h3>"));
return 0;
}
el_val_t el_h4(el_val_t attrs, el_val_t children) {
el_val_t el_h4(el_val_t attrs, el_val_t text) {
if (str_eq(attrs, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("<h4>"), children), EL_STR("</h4>"));
return el_str_concat(el_str_concat(EL_STR("<h4>"), el_escape(text)), EL_STR("</h4>"));
}
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h4 "), attrs), EL_STR(">")), children), EL_STR("</h4>"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<h4 "), attrs), EL_STR(">")), el_escape(text)), EL_STR("</h4>"));
return 0;
}
el_val_t el_button(el_val_t attrs, el_val_t children) {
el_val_t el_button(el_val_t attrs, el_val_t label) {
if (str_eq(attrs, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("<button type=\"button\">"), children), EL_STR("</button>"));
return el_str_concat(el_str_concat(EL_STR("<button type=\"button\">"), el_escape(label)), EL_STR("</button>"));
}
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<button type=\"button\" "), attrs), EL_STR(">")), children), EL_STR("</button>"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("<button type=\"button\" "), attrs), EL_STR(">")), el_escape(label)), EL_STR("</button>"));
return 0;
}
+11 -5
View File
@@ -800,11 +800,17 @@ fn account_download_card() -> String {
el_div(
"class=\"card-dark\" style=\"border-top:3px solid var(--navy)\"",
el_p("class=\"card-label\"", "Download") +
el_p("class=\"download-status\" style=\"color:var(--navy)\"", "Shipping within 30 days") +
el_p("class=\"download-title\"", "Neuron for Mac &amp; Windows") +
el_p("class=\"download-body\"", "macOS and Windows simultaneously. You&#39;ll receive a download link and license key by email the moment it ships. Nothing to do right now.") +
el_button("type=\"button\" class=\"download-btn-disabled\" disabled aria-disabled=\"true\"",
account_signin_svg_download() + " Download arriving soon"
el_p("class=\"download-status\" style=\"color:var(--navy)\"", "Available now &mdash; macOS") +
el_p("class=\"download-title\"", "Neuron for Mac") +
el_p("class=\"download-body\"", "The macOS build (Apple Silicon) is ready to download now. Windows and Linux are coming soon. Your license key is in your launch email.") +
el_div(
"style=\"display:flex;gap:.75rem;flex-wrap:wrap;align-items:center\"",
el_a(
"https://downloads.neurontechnologies.ai/installers/Neuron-1.1.0-macos-arm64.dmg",
"class=\"btn-primary\" download",
account_signin_svg_download() + " Download for macOS"
) +
el_a("/downloads", "class=\"btn-ghost\"", "All platforms &#8594;")
)
)
}
+1 -1
View File
@@ -98,7 +98,7 @@ fn checkout_page(plan: String, pub_key: String) -> String {
el_li("", "Persistent memory - never resets")
+ el_li("", "Local inference via Ollama (coming)")
+ el_li("", "Bring your own API keys")
+ el_li("", "3 marketplace plugins included")
+ el_li("", "Plugin marketplace access (coming soon)")
+ el_li("", "Core built-in capabilities")
+ el_li("", "2 devices included")
} else {
+148
View File
@@ -0,0 +1,148 @@
// components/downloads.el - Public downloads page.
//
// Landing-styled inner page (page_open_seo + nav + content + footer +
// page_close, assembled by main.el). Client-side OS detection via
// navigator.platform highlights the visitor's platform and updates the
// detected-OS banner. macOS is the shipping build; Windows and Linux are
// linked but clearly marked "coming soon" per the current product state
// (Windows chat not yet enabled, Linux soul backend not yet complete).
from nav import { nav }
from footer import { footer }
extern fn el_section(attrs: String, children: String) -> String
extern fn el_div(attrs: String, children: String) -> String
extern fn el_span(attrs: String, children: String) -> String
extern fn el_h1(attrs: String, text: String) -> String
extern fn el_p(attrs: String, children: String) -> String
extern fn el_a(href: String, attrs: String, children: String) -> String
// Scoped presentation. Uses the landing stylesheet's CSS variables
// (--navy, --head, --body, --t2, --t3) so it inherits the site palette.
// No # colors or quoted font names inline routed through vars to stay
// clear of the elc CSS tokenizer edge cases.
fn dl_style() -> String {
"<style>" +
".dl-wrap{max-width:960px}" +
".dl-detected{font-size:.85rem;font-weight:500;color:var(--navy);margin:1.5rem 0 2.5rem;min-height:1.2em}" +
".dl-card{padding:2rem}" +
".dl-featured{border-top:3px solid var(--navy)}" +
".dl-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;margin-top:1.5rem}" +
"@media (max-width:720px){.dl-grid{grid-template-columns:1fr}}" +
".dl-badge{display:inline-block;font-size:.6rem;font-weight:700;letter-spacing:.18em;text-transform:uppercase;padding:.35rem .7rem;border-radius:999px;margin-bottom:1rem}" +
".dl-badge-ready{color:var(--navy);background:rgba(0,82,160,.10)}" +
".dl-badge-soon{color:var(--t3);background:rgba(0,0,0,.05)}" +
".dl-title{font-family:var(--head);font-size:1.4rem;font-weight:600;margin-bottom:.4rem}" +
".dl-sub{font-family:var(--body);font-weight:300;font-size:.9rem;color:var(--t2);line-height:1.6;margin-bottom:1.25rem}" +
".dl-note{font-size:.78rem;color:var(--t3);line-height:1.6;margin-top:1rem}" +
".dl-btnrow{display:flex;gap:.75rem;flex-wrap:wrap;align-items:center}" +
"[data-detected=true]{box-shadow:0 0 0 2px rgba(0,82,160,.45);border-radius:2px}" +
"</style>"
}
fn dl_header() -> String {
el_p("class=\"label reveal\"", "Download") +
el_h1("class=\"display-lg reveal\" style=\"margin-top:.75rem\"", "Get Neuron.") +
el_div("class=\"navy-line-left reveal\" style=\"width:4rem;margin:1.5rem 0 2rem\"", "") +
el_p(
"class=\"dl-sub reveal\" style=\"max-width:34rem;font-size:1rem\"",
"Your AI that remembers you, running on your own machine. macOS is available to download today. Windows and Linux are on the way."
) +
el_p("id=\"os-detected\" class=\"dl-detected reveal\"", "Detecting your platform&#8230;")
}
fn dl_mac_card() -> String {
el_div(
"id=\"card-mac\" class=\"card-dark dl-card dl-featured reveal\"",
el_span("class=\"dl-badge dl-badge-ready\"", "Available now") +
el_p("class=\"dl-title\"", "Neuron for macOS") +
el_p("class=\"dl-sub\"", "Apple Silicon (M1&#8211;M4). macOS 13 Ventura or later.") +
el_div(
"class=\"dl-btnrow\"",
el_a(
"https://downloads.neurontechnologies.ai/installers/Neuron-1.1.0-macos-arm64.dmg",
"class=\"btn-primary\" download",
"Download for macOS &#8594;"
)
) +
el_p("class=\"dl-note\"", "Version 1.1.0 &middot; Apple Silicon &middot; .dmg")
)
}
fn dl_windows_card() -> String {
el_div(
"id=\"card-windows\" class=\"card-dark dl-card reveal\"",
el_span("class=\"dl-badge dl-badge-soon\"", "Coming soon") +
el_p("class=\"dl-title\"", "Neuron for Windows") +
el_p("class=\"dl-sub\"", "Windows 10 and 11 (x64).") +
el_div(
"class=\"dl-btnrow\"",
el_a(
"https://downloads.neurontechnologies.ai/installers/Neuron-1.1.0-windows-x64.msi",
"class=\"btn-ghost\" download",
"Download .msi"
)
) +
el_p(
"class=\"dl-note\"",
"The Windows build is still landing &mdash; this link may not be live yet. Chat is not enabled on Windows in this release."
)
)
}
fn dl_linux_card() -> String {
el_div(
"id=\"card-linux\" class=\"card-dark dl-card reveal\"",
el_span("class=\"dl-badge dl-badge-soon\"", "Coming soon") +
el_p("class=\"dl-title\"", "Neuron for Linux") +
el_p("class=\"dl-sub\"", "Debian / Ubuntu (.deb) or portable (.AppImage), x64.") +
el_div(
"class=\"dl-btnrow\"",
el_a(
"https://downloads.neurontechnologies.ai/installers/Neuron-1.1.0-linux-x64.deb",
"class=\"btn-ghost\" download",
"Download .deb"
) +
el_a(
"https://downloads.neurontechnologies.ai/installers/Neuron-1.1.0-linux-x64.AppImage",
"class=\"btn-ghost\" download",
"Download .AppImage"
)
) +
el_p(
"class=\"dl-note\"",
"Linux packages install today, but the on-device soul backend is still being finished. Full support is coming soon."
)
)
}
fn dl_fineprint() -> String {
el_p(
"class=\"dl-note reveal\" style=\"margin-top:2.5rem\"",
"All installers are served from downloads.neurontechnologies.ai. After checkout your license key arrives by email &mdash; manage it from your " +
el_a("/account", "style=\"color:var(--navy)\"", "account") +
"."
)
}
// Inline OS detection. CSP allows script-src 'unsafe-inline'. Single-quoted
// JS, ASCII only, no // comments keeps the .el string simple and avoids
// tokenizer surprises.
fn dl_script() -> String {
"<script>(function(){var p=(navigator.platform||'')+' '+(navigator.userAgent||'');var os='mac';if(/Win/i.test(p)){os='windows';}else if(/Linux|X11/i.test(p)&&!/Android/i.test(p)){os='linux';}else if(/Mac/i.test(p)){os='mac';}var L={mac:'macOS',windows:'Windows',linux:'Linux'};var b=document.getElementById('os-detected');if(b){b.textContent=(os==='mac')?'We detected macOS on this device. You are ready to download.':('We detected '+L[os]+'. '+L[os]+' support is coming soon; macOS is available to download today.');}var c=document.getElementById('card-'+os);if(c){c.setAttribute('data-detected','true');}})();</script>"
}
fn downloads_content() -> String {
let grid: String = el_div("class=\"dl-grid\"", dl_windows_card() + dl_linux_card())
el_section(
"id=\"downloads\" aria-label=\"Download Neuron\"",
el_div(
"class=\"container dl-wrap\"",
dl_header() + dl_mac_card() + grid + dl_fineprint()
)
)
}
fn downloads_page() -> String {
return nav() + dl_style() + downloads_content() + footer() + dl_script()
}
+17 -3
View File
@@ -1,6 +1,20 @@
// checkout-free.el -- RETIRED. Free plan now uses the standard Stripe
// payment flow (checkout-stripe.el) with a $0 PaymentIntent for age
// verification. This file is no longer compiled or loaded.
// checkout-free.el -- Free plan: show success panel after auth completes.
// Watches the auth-badge element; when it becomes visible, hides the auth
// section and shows the free-success panel. No card required for free tier.
// Compiled with: elc --target=js --bundle --minify --obfuscate
fn main() -> Void {
native_js("(function() {
var success = document.getElementById('free-success');
var auth = document.getElementById('auth-section');
if (!success) return;
var timer = setInterval(function() {
var badge = document.getElementById('auth-badge');
if (badge && badge.offsetParent !== null) {
if (auth) auth.style.display = 'none';
success.style.display = '';
clearInterval(timer);
}
}, 150);
})()")
}
+3 -3
View File
@@ -31,8 +31,8 @@ fn main() -> Void {
if (spinner) spinner.style.display = loading ? '' : 'none';
}
// Free plan: Stripe SetupIntent for age verification (card saved, never charged).
// Falls through to the same Stripe init path — server returns setup_mode=true for free.
// Free plan has no payment form — bail out entirely.
if (str_eq(PLAN, 'free')) return;
window._neuronMode = 'payment';
var paymentEl = null;
@@ -101,7 +101,7 @@ fn main() -> Void {
if (submitLabel) {
submitLabel.textContent = window._neuronMode === 'setup'
? 'Save my card - no charge today →'
: PLAN === 'free' ? 'Verify age & get started →' : 'Complete purchase →';
: 'Complete purchase →';
}
waitForStripe(function() {
if (!stripe) stripe = Stripe(STRIPE_PK);
+24 -12
View File
@@ -87,6 +87,7 @@ from checkout import { checkout_page }
from safety import { safety }
from gallery import { gallery_page }
from account import { account_page }
from downloads import { downloads_page }
// Share-card HTML allowlist
//
@@ -637,7 +638,7 @@ fn handle_request_inner(method: String, path: String, headers: Map, body: String
"Secure your Founding Member spot. Pay once, $199 lifetime — Neuron inference included at launch, priced below the major APIs. First 1,000 only."
} else {
if str_eq(plan, "free") {
"Create your free Neuron account. A card verifies you're 18+ — you won't be charged. Your AI that remembers you, runs on your machine, never resets."
"Create your free Neuron account. No credit card required. Your AI that remembers you runs on your machine, never resets."
} else {
"Subscribe to Neuron Professional for $19/month. The AI that remembers you — persistent memory, runs locally, bring your own API keys."
}
@@ -697,21 +698,23 @@ fn handle_request_inner(method: String, path: String, headers: Map, body: String
}
}
// Free tier: $0 PaymentIntent for age verification (18+ requirement).
// Card is verified and saved (setup_future_usage=off_session). No charge.
// Free tier: creates a SetupIntent for age verification (18+ requirement).
// No charge but the user must provide a valid payment method.
if str_eq(plan, "free") {
let free_pi_body: String = "amount=0"
+ "&currency=usd"
+ "&payment_method_types[]=card"
+ "&setup_future_usage=off_session"
let free_si_body: String = "automatic_payment_methods[enabled]=true"
+ "&usage=off_session"
+ "&metadata[plan]=free"
+ "&metadata[purpose]=age_verification"
let free_pi_body = if !str_eq(pi_cus_id, "") { free_pi_body + "&customer=" + pi_cus_id } else { free_pi_body }
let free_pi_resp: String = http_post_form_auth(
"https://api.stripe.com/v1/payment_intents",
free_pi_body,
let free_si_body = if !str_eq(pi_cus_id, "") { free_si_body + "&customer=" + pi_cus_id } else { free_si_body }
let free_si_resp: String = http_post_form_auth(
"https://api.stripe.com/v1/setup_intents",
free_si_body,
auth_header)
return free_pi_resp
if str_starts_with(free_si_resp, "{") {
let inner: String = str_slice(free_si_resp, 1, str_len(free_si_resp))
return "{\"setup_mode\":true,\"plan\":\"free\"," + inner
}
return free_si_resp
}
// Setup-mode path: save payment method, do not charge. Only valid
@@ -1969,6 +1972,15 @@ fn handle_request_inner(method: String, path: String, headers: Map, body: String
) + badge_css + success_body + page_close()
}
// Downloads
// Public installer page. macOS ships today; Windows/Linux linked but marked
// coming soon. Live-rendered like /about (page shell wraps downloads_page()).
if str_starts_with(path, "/downloads") {
let dl_title: String = "Download Neuron - macOS, Windows & Linux"
let dl_desc: String = "Download Neuron for macOS. Your AI that remembers you, running on your own machine. Windows and Linux support is on the way."
return page_open_seo(dl_title, dl_desc, "/downloads", dl_desc, "false") + downloads_page() + page_close()
}
// Account dashboard
// Use prefix match so OAuth/email-confirmation redirects with query strings still hit.
if str_starts_with(path, "/account") {
+1 -1
View File
@@ -77,7 +77,7 @@ fn marketplace_categories() -> String {
el_div(
"class=\"marketplace-categories reveal\" style=\"transition-delay:320ms\"",
marketplace_tags_block("Connectors - day one", connectors) +
marketplace_tags_block("Connectors (rolling out)", connectors) +
marketplace_tags_block("Following launch", following) +
el_div(
"",
+2 -2
View File
@@ -36,7 +36,7 @@ fn pricing_free_features() -> String {
el_li("", el_span("class=\"dash\"", "-") + el_span("", "Local inference via Ollama (coming)")) +
el_li("", el_span("class=\"dash\"", "-") + el_span("", "Neuron Inference included when it launches - Q3 2026")) +
el_li("", el_span("class=\"dash\"", "-") + el_span("", "Unlimited projects")) +
el_li("", el_span("class=\"dash\"", "-") + el_span("", "3 marketplace plugins included")) +
el_li("", el_span("class=\"dash\"", "-") + el_span("", "Plugin marketplace access (coming soon)")) +
el_li("", el_span("class=\"dash\"", "-") + el_span("", "Core built-in capabilities"))
}
@@ -91,7 +91,7 @@ fn pricing(sold: Int, total: Int) -> String {
el_span("class=\"pricing-price\"", "$0") +
el_span("class=\"pricing-cadence\"", "forever")
) +
el_p("class=\"pricing-tagline\"", "Start building your memory. Card required for age verification — you won't be charged.") +
el_p("class=\"pricing-tagline\"", "Start building your memory. No card required.") +
el_ul("class=\"pricing-features\"", pricing_free_features()) +
el_div("style=\"flex:1\"", "") +
el_div(
+1 -1
View File
@@ -78,7 +78,7 @@ fn page_head() -> String {
return page_head_base()
+ page_seo_block(
"Neuron — The AI That Remembers You",
"Every AI resets when you close the tab. Neuron doesn&#39;t. Runs on your machine. Remembers everything. Start free.",
"Every AI resets when you close the tab. Neuron doesn&#39;t. Runs on your machine. Remembers everything. Start free — no credit card required.",
"/",
"Every other AI forgets you. Neuron doesn&#39;t. Runs on your machine, builds a persistent memory over time, and gets sharper the longer you use it. Free tier available."
)