Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion site/index.html

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions site/island/pricing-island.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,14 @@
@source './LandingPricing.tsx';
/* The SSR fallback markup + dark-band wrapper classes live in index.html. */
@source '../index.html';

/* Because we omit Tailwind's preflight (above), UA <button> chrome leaks in —
* notably a 2px outset border. Re-supply just the button-border normalization,
* scoped to the pricing subtree so it can never touch the landing's own
* buttons. Background and font-size stay on the utility classes (this rule
* deliberately doesn't set them), so it can't override bg-[…]/text-… states. */
#pricing-root button {
border-width: 0;
border-style: solid;
cursor: pointer;
}
6 changes: 3 additions & 3 deletions site/scripts/build-pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export function renderPricingSection(): string {
// Tailwind utilities for the island (theme + utilities, no preflight so the
// landing's own base styles survive).
' <link rel="stylesheet" href="/pricing-island.css" />',
// Dark band so the app-themed dark cards read as an intentional section on
// the light marketing page.
` <div id="pricing-root" class="mx-auto max-w-6xl rounded-3xl bg-[#0b0b0d] px-6 py-16 text-white">${ssr}</div>`,
// No band the pricing section sits directly on the vellum landing, in the
// kernelCAD light palette, so it reads as part of the same page.
` <div id="pricing-root" class="mx-auto max-w-6xl px-2 text-[#0A1628]">${ssr}</div>`,
// Hydrates #pricing-root into the live PricingSection component.
' <script type="module" src="/pricing-island.js"></script>',
' </section>',
Expand Down
14 changes: 7 additions & 7 deletions src/funnel/components/PricingSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,21 @@ export function PricingSection({
<div className="mx-auto max-w-5xl">
{!hideHeading && (
<div className="text-center">
<span className="text-sm font-semibold uppercase tracking-wide text-orange-400">{PRICING_COPY.kicker}</span>
<h2 className="mt-2 font-serif text-4xl font-bold tracking-tight text-white sm:text-5xl">{PRICING_COPY.headline}</h2>
<p className="mx-auto mt-4 max-w-xl text-gray-400">{PRICING_COPY.sub}</p>
<span className="text-sm font-semibold uppercase tracking-wide text-[#1E5FA8]">{PRICING_COPY.kicker}</span>
<h2 className="mt-2 font-serif text-4xl font-bold tracking-tight text-[#0A1628] sm:text-5xl">{PRICING_COPY.headline}</h2>
<p className="mx-auto mt-4 max-w-xl text-[#3F4C5E]">{PRICING_COPY.sub}</p>
</div>
)}

{/* Billing cadence toggle. */}
<div className="mt-8 flex items-center justify-center">
<div className="inline-flex rounded-full bg-[#141416] p-1 ring-1 ring-[#26262b]">
<div className="inline-flex rounded-full bg-[#FFFDF7] p-1 ring-1 ring-[#D6CDB4]">
<button
type="button"
onClick={() => setPeriod('monthly')}
aria-pressed={period === 'monthly'}
className={`rounded-full px-4 py-1.5 text-sm font-medium transition-colors ${
period === 'monthly' ? 'bg-[#2a2a30] text-white' : 'text-gray-400 hover:text-white'
period === 'monthly' ? 'bg-[#1E5FA8] text-white' : 'bg-transparent text-[#3F4C5E] hover:text-[#0A1628]'
}`}
>
Monthly
Expand All @@ -71,10 +71,10 @@ export function PricingSection({
onClick={() => setPeriod('yearly')}
aria-pressed={period === 'yearly'}
className={`rounded-full px-4 py-1.5 text-sm font-medium transition-colors ${
period === 'yearly' ? 'bg-[#2a2a30] text-white' : 'text-gray-400 hover:text-white'
period === 'yearly' ? 'bg-[#1E5FA8] text-white' : 'bg-transparent text-[#3F4C5E] hover:text-[#0A1628]'
}`}
>
Yearly <span className="ml-1 text-emerald-400">· 2 months free</span>
Yearly <span className="ml-1 text-[#B87333]">· 2 months free</span>
</button>
</div>
</div>
Expand Down
46 changes: 24 additions & 22 deletions src/funnel/components/PricingTiers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ import { CONTACT_HREF, TIERS, type BadgeColor, type Feature, type Tier } from '.
*/

const BADGE_CLASS: Record<BadgeColor, string> = {
emerald: 'bg-emerald-500/15 text-emerald-300',
violet: 'bg-violet-500/15 text-violet-300',
amber: 'bg-amber-500/15 text-amber-300',
sky: 'bg-sky-500/15 text-sky-300',
slate: 'bg-slate-500/15 text-slate-300',
// On-brand tints (kernelCAD light palette): blueprint blue + copper + slate,
// so the pricing surface matches the vellum marketing site.
emerald: 'bg-[#1E5FA8]/12 text-[#174E8B]',
sky: 'bg-[#1E5FA8]/12 text-[#174E8B]',
violet: 'bg-[#B87333]/15 text-[#8A551F]',
amber: 'bg-[#B87333]/15 text-[#8A551F]',
slate: 'bg-[#3F4C5E]/12 text-[#3F4C5E]',
};

export interface PricingTiersProps {
Expand All @@ -46,8 +48,8 @@ export interface PricingTiersProps {
function FeatureRow({ f }: { f: Feature }) {
return (
<li className="flex items-start gap-2.5">
<CheckCircle2 size={16} className="mt-0.5 shrink-0 text-emerald-500" />
<span className="text-sm text-gray-200 leading-snug">
<CheckCircle2 size={16} className="mt-0.5 shrink-0 text-[#1E5FA8]" />
<span className="text-sm text-[#3F4C5E] leading-snug">
{f.badge ? (
<span className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${BADGE_CLASS[f.badge]}`}>
{f.emoji && <span>{f.emoji}</span>}
Expand All @@ -59,7 +61,7 @@ function FeatureRow({ f }: { f: Feature }) {
{f.text}
</>
)}
{f.note && <span className="ml-1.5 text-[11px] uppercase tracking-wide text-gray-500">{f.note}</span>}
{f.note && <span className="ml-1.5 text-[11px] uppercase tracking-wide text-[#97A0AC]">{f.note}</span>}
</span>
</li>
);
Expand All @@ -85,37 +87,37 @@ export function PricingTiers({ period, currentPlan, currentTier, onSelect, onFre
<section
key={t.name}
aria-label={`${t.name} plan`}
className={`relative flex flex-col rounded-2xl border p-6 ${
highlight ? 'border-orange-500/60 bg-[#17151a]' : 'border-[#26262b] bg-[#141416]'
className={`relative flex flex-col rounded-2xl p-6 bg-[#FFFDF7] ${
highlight ? 'ring-2 ring-[#1E5FA8]' : 'ring-1 ring-[#D6CDB4]'
}`}
>
{highlight && (
<span className="absolute -top-3 left-6 rounded-full bg-gradient-to-r from-orange-500 to-red-500 px-3 py-0.5 text-xs font-semibold text-white shadow">
<span className="absolute -top-3 left-6 rounded-full bg-[#1E5FA8] px-3 py-0.5 text-xs font-semibold text-white shadow">
Most popular
</span>
)}

<h3 className="text-2xl font-bold text-white">{t.name}</h3>
<h3 className="text-2xl font-bold text-[#0A1628]">{t.name}</h3>
<div className="mt-2 flex items-end gap-2">
<span className="text-5xl font-extrabold tracking-tight text-white">
<span className="text-5xl font-extrabold tracking-tight text-[#0A1628]">
{showYearly ? t.yearlyPerMonth : t.monthly}
</span>
<span className="mb-1.5 text-sm text-gray-400">
<span className="mb-1.5 text-sm text-[#97A0AC]">
{t.contact ? "let's talk" : paid ? (showYearly ? '/mo · billed yearly' : 'per month') : t.monthly === '$0' ? 'forever' : ''}
</span>
</div>
{showYearly ? (
<p className="mt-1 text-xs text-emerald-400">{t.yearly}/year — 2 months free</p>
<p className="mt-1 text-xs text-[#B87333]">{t.yearly}/year — 2 months free</p>
) : (
<p className="mt-1 text-xs text-transparent select-none" aria-hidden="true">.</p>
)}
<p className="mt-3 min-h-[40px] text-sm text-gray-400">{t.blurb}</p>
<p className="mt-3 min-h-[40px] text-sm text-[#3F4C5E]">{t.blurb}</p>

{t.contact ? (
<a
href={CONTACT_HREF}
aria-label="Contact sales about Enterprise"
className="mt-5 w-full rounded-lg bg-[#26262b] py-3 text-center text-sm font-semibold text-white no-underline transition-colors hover:bg-[#31313a]"
className="mt-5 w-full rounded-lg bg-[#EFE5C9] py-3 text-center text-sm font-semibold text-[#0A1628] no-underline transition-colors hover:bg-[#E3D6B4]"
>
Contact sales
</a>
Expand All @@ -125,7 +127,7 @@ export function PricingTiers({ period, currentPlan, currentTier, onSelect, onFre
onClick={onFree}
disabled={current}
aria-label={current ? 'Current plan (Free)' : 'Get started with Free'}
className="mt-5 w-full rounded-lg bg-[#26262b] py-3 text-sm font-semibold text-white transition-colors hover:bg-[#31313a] disabled:cursor-default disabled:opacity-60"
className="mt-5 w-full rounded-lg bg-[#EFE5C9] py-3 text-sm font-semibold text-[#0A1628] transition-colors hover:bg-[#E3D6B4] disabled:cursor-default disabled:opacity-60"
>
{current ? 'Current plan' : 'Get started'}
</button>
Expand All @@ -135,10 +137,10 @@ export function PricingTiers({ period, currentPlan, currentTier, onSelect, onFre
onClick={() => onSelect(t.tier as PaidTier, period)}
disabled={current || busy}
aria-label={current ? `Current plan (${t.name})` : `Subscribe to ${t.name}`}
className={`mt-5 w-full rounded-lg py-3 text-sm font-semibold text-white transition-colors disabled:cursor-default disabled:opacity-70 ${
className={`mt-5 w-full rounded-lg py-3 text-sm font-semibold transition-colors disabled:cursor-default disabled:opacity-70 ${
highlight
? 'bg-gradient-to-r from-orange-500 to-red-500 hover:from-orange-400 hover:to-red-400'
: 'bg-[#26262b] hover:bg-[#31313a]'
? 'bg-[#1E5FA8] text-white hover:bg-[#174E8B]'
: 'bg-[#EFE5C9] text-[#0A1628] hover:bg-[#E3D6B4]'
}`}
>
{current ? 'Current plan' : busy ? 'Loading…' : 'Subscribe →'}
Expand All @@ -147,7 +149,7 @@ export function PricingTiers({ period, currentPlan, currentTier, onSelect, onFre

<ul className="mt-6 space-y-3">
{t.inherits && (
<li className="text-sm font-medium text-gray-300 underline decoration-dotted underline-offset-4">
<li className="text-sm font-medium text-[#3F4C5E] underline decoration-dotted underline-offset-4">
← Everything in {t.inherits}, plus:
</li>
)}
Expand Down
16 changes: 8 additions & 8 deletions src/studio/routes/pricing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,26 +68,26 @@ function PricingPage() {
};

return (
<main className="min-h-screen bg-[#0b0b0d] text-white font-sans">
<main className="min-h-screen bg-[#F4ECD7] text-[#0A1628] font-sans">
{/* Nav */}
<header className="flex items-center justify-between px-6 py-4">
<a href="/" className="flex items-center gap-2 font-serif text-base font-medium no-underline text-white">
<svg className="w-4 h-4 text-white" viewBox="0 0 84 84" fill="none" aria-label="kernelCAD">
<a href="/" className="flex items-center gap-2 font-serif text-base font-medium no-underline text-[#0A1628]">
<svg className="w-4 h-4 text-[#0A1628]" viewBox="0 0 84 84" fill="none" aria-label="kernelCAD">
<path d="M 14,12 L 26,12 L 26,34 Q 26,36 27.5,34.5 L 46,12 L 60,12 L 36,40 Q 35,42 36,44 L 60,72 L 46,72 L 27.5,49.5 Q 26,48 26,50 L 26,72 L 14,72 Z" fill="currentColor"/>
</svg>
<span>kernel<span className="text-blue-400">CAD</span></span>
<span>kernel<span className="text-[#1E5FA8]">CAD</span></span>
</a>
<a
href={session ? '/billing' : '/signin'}
className="rounded-lg px-3 py-1.5 text-xs font-medium text-gray-300 hover:text-white no-underline transition-colors"
className="rounded-lg px-3 py-1.5 text-xs font-medium text-[#3F4C5E] hover:text-[#0A1628] no-underline transition-colors"
>
{session ? 'Billing' : 'Log in'}
</a>
</header>

<section className="mx-auto max-w-5xl px-6 pb-20 pt-10">
<h1 className="text-center font-serif text-5xl font-bold tracking-tight">Pricing</h1>
<p className="mx-auto mt-4 max-w-xl text-center text-gray-400">
<h1 className="text-center font-serif text-5xl font-bold tracking-tight text-[#0A1628]">Pricing</h1>
<p className="mx-auto mt-4 max-w-xl text-center text-[#3F4C5E]">
A monthly token allowance for the parametric build agent — a tiny cube costs a sliver, a big assembly costs more. Cancel anytime.
</p>

Expand All @@ -104,7 +104,7 @@ function PricingPage() {
/>
</div>

<p className="mt-10 text-center text-xs text-gray-500">
<p className="mt-10 text-center text-xs text-[#97A0AC]">
Prices in USD. Cancel anytime. Failed generations don't count against your quota.
</p>
</section>
Expand Down
Loading