Files
neuron-web/src/checkout.el
T
will.anderson c72127032e
Dev — Build & local smoke test / build-smoke (pull_request) Successful in 1m18s
Fix initStripe load order, subscription webhook email extraction, chat textarea UX
- checkout.el: swap stripe_el_script before auth_script so initStripe is
  defined when Supabase auth fires onAuthStateChange on page load
- main.el: fix Stripe webhook email extraction for checkout.session.completed
  (subscription) events — customer_details is nested at data.object level,
  not at root; previous code only worked for payment_intent.succeeded
- page_close.c: replace <input type="text"> with <textarea rows="1"> in
  the chat widget input row so long questions are visible as you type
- page_css.c: update #neuron-demo-text CSS for textarea (resize:none,
  overflow:hidden, min/max-height, align-items:flex-end on row)
- chat-widget.el: add auto-resize event listener (grows up to ~4 lines),
  reset height to auto on send
2026-05-12 12:22:59 -05:00

614 lines
26 KiB
EmacsLisp

// 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
// el-html vessel extern declarations (implementations in dist/elhtml_impl.c)
extern fn el_escape(s: String) -> String
extern fn el_text(s: String) -> String
extern fn el_attr(name: String, value: String) -> String
extern fn el_div(attrs: String, children: String) -> String
extern fn el_section(attrs: String, children: String) -> String
extern fn el_article(attrs: String, children: String) -> String
extern fn el_header(attrs: String, children: String) -> String
extern fn el_footer(attrs: String, children: String) -> String
extern fn el_main(attrs: String, children: String) -> String
extern fn el_nav(attrs: String, children: String) -> String
extern fn el_aside(attrs: String, children: String) -> String
extern fn el_ul(attrs: String, children: String) -> String
extern fn el_ol(attrs: String, children: String) -> String
extern fn el_li(attrs: String, children: String) -> String
extern fn el_p(attrs: String, children: String) -> String
extern fn el_span(attrs: String, children: String) -> String
extern fn el_form(attrs: String, children: String) -> String
extern fn el_h1(attrs: String, text: String) -> String
extern fn el_h2(attrs: String, text: String) -> String
extern fn el_h3(attrs: String, text: String) -> String
extern fn el_h4(attrs: String, text: String) -> String
extern fn el_button(attrs: String, label: String) -> String
extern fn el_a(href: String, attrs: String, children: String) -> String
extern fn el_input(type_attr: String, attrs: String) -> String
extern fn el_textarea(attrs: String, value: String) -> String
extern fn el_label(for_id: String, attrs: String, children: String) -> String
extern fn el_img(src: String, alt: String, attrs: String) -> String
extern fn el_strong(children: String) -> String
extern fn el_em(children: String) -> String
extern fn el_code(children: String) -> String
extern fn el_pre(attrs: String, children: String) -> String
extern fn el_hr() -> String
extern fn el_br() -> String
extern fn el_html_doc(lang: String, head_html: String, body_html: String) -> String
extern fn el_meta(name: String, content: String) -> String
extern fn el_meta_charset(charset: String) -> String
extern fn el_link_stylesheet(href: String) -> String
extern fn el_script_src(src: String, defer_load: Bool) -> String
extern fn el_script_inline(js: String) -> String
extern fn el_title(text: String) -> String
fn el_style_block(css: String) -> String {
"<style>" + css + "</style>"
}
fn checkout_nav_html() -> String {
let logo_img: String = el_img(
"/assets/brand/neuron-wordmark-on-light.png",
"Neuron",
"srcset=\"/assets/brand/neuron-wordmark-on-light@2x.png 2x\" height=\"28\""
)
let logo_link: String = el_a("/", "class=\"nav-logo\" aria-label=\"Neuron home\"", logo_img)
let back_link: String = el_a("/", "class=\"nav-link\"", "&#8592; Back")
let nav_links: String = el_div("class=\"nav-links\"", back_link)
let nav_inner: String = el_div("class=\"nav-inner\"", logo_link + nav_links)
el_nav("id=\"nav\"", nav_inner)
}
fn checkout_page(plan: String, pub_key: String) -> String {
let is_founding: Bool = str_eq(plan, "founding")
let is_free: Bool = str_eq(plan, "free")
let plan_name: String = if is_founding { "Founding Member" } else { if is_free { "Free" } else { "Professional" } }
let plan_price: String = if is_founding { "$199" } else { if is_free { "$0" } else { "$19 / month" } }
let plan_desc: String = if is_founding {
"Pay once. Neuron inference when it launches - priced below the major APIs. No subscription, ever."
} else { if is_free {
"Start building your memory. A card verifies you're 18+. You won't be charged."
} else {
"Full access. Bring your own API keys or use Neuron Inference when it launches - Q3 2026."
} }
let plan_cadence: String = if is_founding { "one-time" } else { if is_free { "forever" } else { "billed monthly" } }
let features_html: String = if is_founding {
el_li("", "Everything in Professional - forever")
+ el_li("", "Neuron Inference when it launches - priced below the major APIs, forever")
+ el_li("", "Never pay again - lifetime updates included")
+ el_li("", "Founding member badge in the app")
+ el_li("", "Private founding member community")
+ el_li("", "Shape the roadmap - your votes carry more weight")
+ el_li("", "Beta features before general release")
+ el_li("", "Name in the credits")
} else { if is_free {
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("", "Core built-in capabilities")
+ el_li("", "2 devices included")
} else {
el_li("", "Persistent memory - never resets")
+ el_li("", "Bring your own API keys (OpenAI, Anthropic, Grok...)")
+ el_li("", "Neuron Inference when it launches - Q3 2026, priced below the major APIs")
+ el_li("", "Unlimited projects")
+ el_li("", "Full plugin marketplace")
+ el_li("", "IDE, Slack, and more integrations")
+ el_li("", "Early access to new features")
+ el_li("", "2 devices included")
} }
let nav_html: String = checkout_nav_html()
// Order summary (left column)
let price_row: String = el_div(
"style=\"display: flex; align-items: baseline; gap: .5rem; margin-top: 1.25rem;\"",
el_span("class=\"checkout-price\"", el_text(plan_price))
+ el_span("class=\"checkout-cadence\"", el_text(plan_cadence))
)
let plan_block: String = el_div(
"style=\"margin-bottom: 2rem;\"",
el_p("class=\"checkout-plan-name\"", el_text(plan_name))
+ el_p("class=\"checkout-plan-desc\"", el_text(plan_desc))
+ price_row
)
let summary_col: String = el_div(
"class=\"checkout-summary\"",
el_p("class=\"label\" style=\"margin-bottom: 1.5rem; color: var(--navy);\"", "Your order")
+ plan_block
+ el_div("class=\"navy-line-left\" style=\"width: 3rem; margin-bottom: 1.75rem;\"", "")
+ el_ul("class=\"checkout-features\"", features_html)
+ el_p("class=\"checkout-guarantee\"", "Your data stays yours. Runs locally. No telemetry.")
)
// Auth section
let auth_heading: String = if is_free {
el_p("class=\"label\" style=\"margin-bottom: 1.5rem; color: var(--navy);\"", "Create your account.")
+ el_p("class=\"checkout-auth-hint\" style=\"margin-bottom: 2rem;\"", "Create your account. We'll ask for a card to verify your age - you won't be charged.")
} else {
el_p("class=\"label\" style=\"margin-bottom: 1.25rem;\"", "Sign in (optional)")
+ el_p("class=\"checkout-auth-hint\"", "Sign in to link this purchase to an existing account. Or skip and create one later - we'll match it to your email.")
}
let google_svg: String = "<svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" aria-hidden=\"true\">"
+ "<path d=\"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z\" fill=\"#4285F4\"/>"
+ "<path d=\"M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z\" fill=\"#34A853\"/>"
+ "<path d=\"M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332z\" fill=\"#FBBC05\"/>"
+ "<path d=\"M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 6.29C4.672 4.163 6.656 3.58 9 3.58z\" fill=\"#EA4335\"/>"
+ "</svg>"
let github_svg: String = "<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">"
+ "<path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.385-1.335-1.755-1.335-1.755-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.605-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 21.795 24 17.298 24 12c0-6.63-5.37-12-12-12z\"/>"
+ "</svg>"
let social_btns: String = el_div(
"class=\"checkout-social-btns\"",
"<button type=\"button\" class=\"checkout-social-btn\" id=\"btn-google\" onclick=\"signInWith('google')\">"
+ google_svg + "Continue with Google</button>"
+ "<button type=\"button\" class=\"checkout-social-btn\" id=\"btn-github\" onclick=\"signInWith('github')\">"
+ github_svg + "Continue with GitHub</button>"
)
let auth_message: String = el_div("id=\"auth-message\" class=\"checkout-message\" style=\"display:none;\"", "")
let divider_label: String = if is_free {
"or create an account with email"
} else {
"or create an account"
}
let auth_divider: String = el_div(
"class=\"checkout-auth-divider\"",
el_span("id=\"auth-divider-label\"", divider_label)
)
let create_btn_label: String = if is_free { "Create account &#8594;" } else { "Create account &rarr;" }
let email_auth_form: String = el_div(
"id=\"email-auth-form\"",
el_input("email", "id=\"auth-email\" class=\"checkout-input\" placeholder=\"Email address\" autocomplete=\"email\" style=\"width:100%;display:block;margin-bottom:.75rem\"")
+ el_input("password", "id=\"auth-password\" class=\"checkout-input\" placeholder=\"Password - min 8 characters\" autocomplete=\"new-password\" style=\"width:100%;display:block;margin-bottom:.75rem\"")
+ "<button type=\"button\" class=\"checkout-email-btn\" onclick=\"signUpWithEmail()\">" + create_btn_label + "</button>"
+ el_p("class=\"checkout-auth-hint\" style=\"margin-top:.75rem;text-align:center\"",
"Already have an account? "
+ el_a("#", "onclick=\"showSignIn();return false;\" style=\"color:var(--navy)\"", "Sign in")
)
)
let auth_section_style: String = if is_free { "" } else { "display:none;" }
let auth_section: String = el_div(
"id=\"auth-section\" style=\"" + auth_section_style + "\"",
auth_heading + social_btns + auth_message + auth_divider + email_auth_form
)
// Free-tier success panel
let free_success: String = ""
// Payment section
let payment_section_style: String = if is_free { "display:none;" } else { "" }
let auth_badge: String = el_div("id=\"auth-badge\" style=\"display:none; margin-bottom: 1.5rem;\"", "")
let signin_prompt: String = if is_free { "" } else {
el_p(
"class=\"checkout-auth-hint\" id=\"signin-prompt\" style=\"margin-bottom:1.25rem;font-size:.8125rem\"",
"Already have an account? "
+ el_a(
"#",
"onclick=\"document.getElementById('auth-section').style.display='';this.parentNode.style.display='none';return false;\" style=\"color:var(--navy);text-decoration:underline\"",
"Sign in"
)
+ " to link your purchase."
)
}
let founding_attestation: String = if is_founding {
el_div(
"id=\"founding-attestation\" style=\"margin-bottom:2rem;padding:1.5rem;border:1px solid rgba(0,82,160,.2);background:rgba(0,82,160,.03)\"",
el_p("style=\"font-family:var(--body);font-weight:500;font-size:.9rem;color:var(--t1);margin-bottom:.75rem\"", "Before you continue")
+ el_p("style=\"font-family:var(--body);font-weight:300;font-size:.8375rem;color:var(--t2);line-height:1.75;margin-bottom:1.25rem\"",
"Founding Member is not a ceremonial title. These are the people who will work directly with the team to shape what Neuron becomes. You will have a real voice in what gets built, and we will take it seriously. That requires you to show up in good faith."
)
+ "<label style=\"display:flex;gap:.875rem;align-items:flex-start;cursor:pointer\">"
+ el_input("checkbox", "id=\"founding-attest-cb\" style=\"margin-top:.2rem;width:16px;height:16px;flex-shrink:0;accent-color:var(--navy)\"")
+ el_span(
"style=\"font-family:var(--body);font-weight:300;font-size:.8125rem;color:var(--t2);line-height:1.7\"",
"I am joining as a genuine early user, not to extract proprietary information about Neuron&#39;s technology, architecture, or roadmap. I will engage in good faith. I understand that if this is not my intent, a different plan is a better fit."
)
+ "</label>"
+ el_p("id=\"attest-warn\" style=\"display:none;font-family:var(--body);font-size:.8rem;color:#c44;margin-top:.75rem\"", "Please confirm the above before continuing.")
)
} else { "" }
let charge_timing: String = if is_founding || is_free { "" } else {
el_div(
"style=\"margin-bottom:1.75rem\"",
el_p("class=\"label\" style=\"margin-bottom:1rem\"", "When would you like to be charged?")
+ el_div(
"style=\"display:flex;flex-direction:column;gap:.625rem\"",
"<label class=\"checkout-timing-opt\" id=\"timing-now-label\">"
+ el_input("radio", "name=\"charge-timing\" value=\"now\" id=\"timing-now\" checked style=\"accent-color:var(--navy)\"")
+ el_div("",
el_span("style=\"font-family:var(--body);font-weight:500;font-size:.875rem;color:var(--t1)\"", "Charge me now")
+ el_span("style=\"font-family:var(--body);font-weight:300;font-size:.8rem;color:var(--t3);display:block;margin-top:.15rem\"",
"Paying now signals you're serious. It gives us real signal about what people actually want to use Neuron for - not just who's curious. That shapes what we build first."
)
)
+ "</label>"
+ "<label class=\"checkout-timing-opt\" id=\"timing-later-label\">"
+ el_input("radio", "name=\"charge-timing\" value=\"later\" id=\"timing-later\" style=\"accent-color:var(--navy)\"")
+ el_div("",
el_span("style=\"font-family:var(--body);font-weight:500;font-size:.875rem;color:var(--t1)\"", "Hold until product launches (Q3 2026)")
+ el_span("style=\"font-family:var(--body);font-weight:300;font-size:.8rem;color:var(--t3);display:block;margin-top:.15rem\"",
"We save your payment method securely. Nothing charged until launch. Cancel anytime before then."
)
)
+ "</label>"
)
)
}
let security_svg: String = "<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>"
let submit_label: String = if is_free { "Verify age &amp; get started &#8594;" } else { "Complete purchase &#8594;" }
let payment_form: String = el_form(
"id=\"payment-form\" autocomplete=\"on\"",
el_div(
"class=\"checkout-field-group\"",
el_div("class=\"checkout-field\"",
el_label("buyer-name", "class=\"checkout-label\"", "Full name")
+ el_input("text", "id=\"buyer-name\" name=\"name\" autocomplete=\"name\" class=\"checkout-input\" placeholder=\"Full name\" required")
)
+ el_div("class=\"checkout-field\"",
el_label("buyer-email", "class=\"checkout-label\"", "Email")
+ el_input("email", "id=\"buyer-email\" name=\"email\" autocomplete=\"email\" class=\"checkout-input\" placeholder=\"you@example.com\" required")
)
)
+ el_div(
"class=\"checkout-payment-element-wrap\"",
el_div("id=\"payment-element\"",
el_div("class=\"checkout-element-loading\"", "Loading payment form&#8230;")
)
)
+ el_div("id=\"payment-message\" class=\"checkout-message\" style=\"display:none;\"", "")
+ "<button id=\"submit-btn\" class=\"checkout-submit\" type=\"submit\" disabled>"
+ el_span("id=\"submit-label\"", submit_label)
+ el_span("id=\"submit-spinner\" style=\"display:none;\"", "Processing&#8230;")
+ "</button>"
+ el_p("class=\"checkout-security\"",
security_svg
+ " Secured by Stripe &nbsp;&middot;&nbsp; 256-bit TLS &nbsp;&middot;&nbsp; PCI DSS compliant"
)
)
let payment_section: String = el_div(
"id=\"payment-section\" style=\"" + payment_section_style + "\"",
auth_badge
+ signin_prompt
+ founding_attestation
+ charge_timing
+ el_p("class=\"label\" style=\"margin-bottom: 1.75rem;\"", "Payment")
+ payment_form
)
// Right column
let form_wrap: String = el_div(
"class=\"checkout-form-wrap\"",
auth_section + free_success + payment_section
)
// Full page shell
let checkout_shell: String = el_div("class=\"checkout-shell\"", summary_col + form_wrap)
let main_html: String = el_main(
"style=\"min-height: 100vh; padding: clamp(6rem, 14vh, 9rem) 2rem 4rem;\"",
checkout_shell
)
let style_html: String = checkout_style_html()
let supabase_script: String = el_script_src("https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2/dist/umd/supabase.js", false)
let stripe_script: String = "<script src=\"https://js.stripe.com/v3/\" async></script>"
let auth_script: String = el_script_src("/js/checkout-auth.js", true)
let cfg_js: String = "window.NEURON_CFG=window.NEURON_CFG||{};window.NEURON_CFG.plan=\"" + plan + "\";window.NEURON_CFG.pub_key=\"" + pub_key + "\";"
let cfg_script: String = el_script_inline(cfg_js)
let stripe_el_script: String = el_script_src("/js/checkout-stripe.js", true)
let free_init_script: String = ""
return nav_html + main_html + supabase_script + stripe_script + style_html + stripe_el_script + cfg_script + auth_script + free_init_script
}
fn checkout_style_html() -> String {
let css: String = ".checkout-shell {
max-width: 980px;
margin: 0 auto;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4rem;
align-items: start;
}
.checkout-summary {
position: sticky;
top: 2rem;
}
.checkout-form-wrap {
min-width: 0;
}
@media (max-width: 860px) {
.checkout-shell {
grid-template-columns: 1fr;
gap: 2.5rem;
}
.checkout-summary {
position: static;
}
}
.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;
width: 100%;
box-sizing: border-box;
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;
}
.checkout-auth-hint {
font-family: var(--body);
font-weight: 300;
font-size: .875rem;
color: var(--t2);
line-height: 1.6;
margin: 0 0 1.75rem;
}
.checkout-social-btns {
display: flex;
flex-direction: column;
gap: .75rem;
margin-bottom: 1.75rem;
}
.checkout-social-btn {
display: flex;
align-items: center;
gap: .875rem;
width: 100%;
padding: .875rem 1.25rem;
background: #fff;
border: 1.5px solid rgba(0,82,160,.18);
font-family: var(--body);
font-size: .9375rem;
font-weight: 500;
color: var(--t1);
cursor: pointer;
transition: border-color .2s, background .2s, box-shadow .2s;
text-align: left;
border-radius: 0;
letter-spacing: .01em;
}
.checkout-social-btn:hover {
border-color: var(--navy);
background: rgba(0,82,160,.03);
box-shadow: 0 2px 12px rgba(0,82,160,.08);
}
.checkout-social-btn:disabled { opacity: .45; cursor: not-allowed; }
.checkout-auth-divider {
display: flex;
align-items: center;
gap: 1rem;
margin: 1.75rem 0 1.25rem;
color: var(--t3);
font-family: var(--body);
font-size: .75rem;
font-weight: 500;
letter-spacing: .12em;
text-transform: uppercase;
}
.checkout-auth-divider::before,
.checkout-auth-divider::after {
content: '';
flex: 1;
height: 1px;
background: rgba(0,82,160,.12);
}
.checkout-email-btn {
display: block;
width: 100%;
padding: .875rem 1.5rem;
background: var(--navy);
color: #fff;
border: none;
font-family: var(--body);
font-size: .8125rem;
font-weight: 500;
letter-spacing: .12em;
text-transform: uppercase;
cursor: pointer;
margin-top: .75rem;
transition: background .2s, box-shadow .2s;
}
.checkout-email-btn:hover { background: #0078D4; box-shadow: 0 2px 16px rgba(0,82,160,.25); }
.checkout-skip-btn {
background: none;
border: none;
font-family: var(--body);
font-size: .8125rem;
color: var(--t3);
cursor: pointer;
text-decoration: underline;
text-underline-offset: 3px;
padding: 0;
}
.checkout-skip-btn:hover { color: var(--navy); }
.checkout-auth-badge {
display: flex;
align-items: center;
gap: .6rem;
padding: .6rem .875rem;
background: rgba(0,82,160,.05);
border: 1px solid rgba(0,82,160,.18);
font-family: var(--body);
font-size: .8125rem;
color: var(--t2);
}
.checkout-auth-badge strong { color: var(--navy); font-weight: 500; }"
el_style_block(css)
}