Pricing blocks
Plan comparison layouts that make tiers, features, and the upgrade path easy to scan.
Comparison table
Full feature matrix across three plans, with a monthly/annual toggle that re-prices the header from one client signal
-
components
-
plan_matrix
-
-
templates
-
pages
-
<script>
function ardenPeriod(annual) {
return {
annual: annual,
monthlyStyle: annual ? 'ghost' : '',
annualStyle: annual ? '' : 'ghost',
suffix: annual ? '/year' : '/month',
note: annual ? 'Billed once a year. Two months on us.' : 'Billed monthly. Cancel any time.'
};
}
</script>
<c-lbr.signals id="matrix-period" :$period=period />
<main class="container mx-auto max-w-5xl px-4 py-16 flex flex-col gap-12">
<c-plan-matrix.header />
<c-plan-matrix.matrix :plans=plans :groups=groups />
<c-plan-matrix.footnote />
</main>
<c-vars value="" />
{% if value == "yes" %}
<c-lbi n="rmx.checkbox-circle" w="18" h="18" class="inline-block text-success" />
{% elif value == "no" %}
<c-lbi n="rmx.subtract" w="18" h="18" class="inline-block text-base-content/25" />
{% else %}
<span class="text-sm tabular-nums text-base-content/80">{{ value }}</span>
{% endif %}
<div class="grid gap-6 md:grid-cols-3 border-t border-base-300 pt-8">
<div class="md:col-span-2 flex flex-col gap-3">
<h2 class="text-sm font-semibold">The lines people ask about</h2>
<p class="text-sm text-base-content/60">
A tracked customer is one that had a live subscription at any point in the
month. Cancelled customers stay in your history and stop counting the month
after they churn, so a bad quarter never inflates your bill.
</p>
<p class="text-sm text-base-content/60">
Seats are named, not concurrent. Read-only viewers — board members, auditors,
your accountant — do not take a seat on any plan.
</p>
</div>
<c-lb.card class="bg-base-200/50">
<c-lb.card.body class="gap-3 p-5">
<c-lb.badge style="soft" size="sm" icon="rmx.customer-service-2">Not sure?</c-lb.badge>
<p class="text-sm text-base-content/70">
Send us last month's Stripe export and we will tell you which plan you
land on. No call, no demo.
</p>
<c-lb.button size="sm" btnStyle="outline" icon="rmx.mail-send">Email our team</c-lb.button>
</c-lb.card.body>
</c-lb.card>
</div>
<div class="flex flex-col items-center gap-5 text-center">
<h1 class="text-4xl font-semibold tracking-tight text-balance">
Compare every Arden plan
</h1>
<p class="max-w-xl text-base-content/60">
The same revenue graph underneath all three. What changes is how much of it you
can automate, and who you can hand it to.
</p>
<c-lb.join class="mt-2 p-1 bg-base-200 rounded-lg">
<c-lb.button
data-lbb-start
type="button"
class="join-item"
size="sm"
variant="primary"
btnStyle="$period.monthlyStyle:"
data-on:click="$period = ardenPeriod(false)"
>Monthly</c-lb.button>
<c-lb.button
type="button"
class="join-item"
size="sm"
variant="primary"
btnStyle="$period.annualStyle:ghost"
data-on:click="$period = ardenPeriod(true)"
>Annual</c-lb.button>
</c-lb.join>
<p class="text-xs text-base-content/50" data-text="$period.note">
Billed monthly. Cancel any time.
</p>
</div>
<c-vars :plans="[]" :groups="[]" />
<div class="overflow-x-auto rounded-lg border border-base-300">
<c-lb.table class="w-full">
<thead>
<tr>
<th class="w-2/5 bg-base-100"></th>
{% for plan in plans %}
<th class="align-top {% if plan.featured %}bg-primary/5{% else %}bg-base-100{% endif %}">
<div class="flex flex-col gap-2 py-3">
<div class="flex items-center gap-2">
<span class="text-base font-semibold">{{ plan.name }}</span>
{% if plan.featured %}
<c-lb.badge variant="primary" size="xs">Popular</c-lb.badge>
{% endif %}
</div>
<div class="flex items-baseline gap-1">
<span class="text-sm font-medium text-base-content/70">$</span>
<span
id="matrix-price-{{ plan.name|lower }}"
class="text-3xl font-bold tabular-nums"
data-text="$period.annual ? '{{ plan.annual }}' : '{{ plan.monthly }}'"
>{{ plan.monthly }}</span>
<span
class="text-xs font-normal text-base-content/50"
data-text="$period.suffix"
>/month</span>
</div>
<p class="text-xs font-normal text-base-content/50">{{ plan.tagline }}</p>
{% if plan.featured %}
<c-lb.button size="sm" variant="primary">{{ plan.cta }}</c-lb.button>
{% else %}
<c-lb.button size="sm" btnStyle="outline">{{ plan.cta }}</c-lb.button>
{% endif %}
</div>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for group in groups %}
<tr>
<th
colspan="4"
class="bg-base-200 text-xs uppercase tracking-wider text-base-content/50"
>{{ group.name }}</th>
</tr>
{% for row in group.rows %}
<tr class="hover:bg-base-200/40">
<td class="text-sm font-medium">{{ row.label }}</td>
{% for value in row.values %}
<td class="text-center">
<c-plan-matrix.cell :value=value />
</td>
{% endfor %}
</tr>
{% endfor %}
{% endfor %}
</tbody>
</c-lb.table>
</div>
Learn from this block
-
Prop mode: an object literal straight from the page context. No schema, no view, no endpoint — the matrix is a static page with one moving part.
-
`$period.annualStyle` is the signal, `ghost` is what the server renders. The button picks up its daisyUI classes again in the browser when the signal moves.
-
Each column header reads the same signal. Flipping to annual re-renders all three prices at once and the network tab stays empty — the annual figures were already in the HTML.
-
Tick, dash or a value — decided once, in one small component, so the table body stays an outline you can read. The icon colours come from theme tokens, so the matrix survives every daisyUI theme.
Highlight tiers
Three plans with the middle one raised on a theme-token gradient — static, and ships zero JavaScript
-
components
-
highlight_tiers
-
-
templates
-
pages
-
<main class="container mx-auto max-w-6xl px-4 py-16 flex flex-col gap-12">
<div class="flex flex-col items-center gap-4 text-center">
<h1 class="text-4xl sm:text-5xl font-semibold tracking-tight text-balance">
Three plans. Most teams pick the middle one.
</h1>
<p class="max-w-xl text-base-content/60">
Prices are per workspace, per month, and include every seat listed. Annual
billing takes two months off, and you can move between plans whenever the
numbers say so.
</p>
</div>
<div class="grid gap-6 lg:grid-cols-3 items-stretch">
{% for plan in plans %}
<c-highlight-tiers.tier :plan=plan />
{% endfor %}
</div>
<c-highlight-tiers.proof :stats=stats />
</main>
<c-vars :stats="[]" />
<div class="flex flex-col gap-10 border-t border-base-300 pt-10">
<div class="grid gap-8 md:grid-cols-3">
{% for stat in stats %}
<div class="flex flex-col gap-1">
<span class="text-3xl font-bold tracking-tight tabular-nums">{{ stat.value }}</span>
<span class="text-sm text-base-content/60">{{ stat.label }}</span>
</div>
{% endfor %}
</div>
<div class="grid gap-8 md:grid-cols-3 items-center">
<c-lb.card class="md:col-span-2 bg-base-200/50">
<c-lb.card.body class="gap-4 p-6">
<p class="text-sm leading-relaxed">
“Growth was the right call on day one and we have never had a reason
to move. The renewal alerts alone caught two contracts we had
forgotten were up.”
</p>
<div class="flex items-center gap-3">
<c-lb.avatar placeholder initials="TN" bgColor="primary" size="sm" />
<div class="text-xs">
<div class="font-medium">Tomas Neary</div>
<div class="text-base-content/50">VP Finance, Northwind Co</div>
</div>
</div>
</c-lb.card.body>
</c-lb.card>
<div class="flex flex-col gap-3">
<p class="text-xs uppercase tracking-wider text-base-content/40">
Also using Arden
</p>
<div class="flex flex-wrap gap-x-5 gap-y-2 text-sm font-medium text-base-content/50">
<span>AtlasForge</span>
<span>Kite & Bell</span>
<span>Verity Labs</span>
<span>Ironvale Group</span>
</div>
</div>
</div>
</div>
<c-vars :plan="{}" />
<c-lb.card
border
class="h-full bg-base-100 {% if plan.featured %}border-primary border-2 shadow-lg ring-1 ring-primary/20{% endif %}"
>
<c-lb.card.body class="gap-5">
<div class="flex items-center justify-between gap-3">
<h2 class="text-lg font-semibold">{{ plan.name }}</h2>
{% if plan.featured %}
<c-lb.badge variant="primary" size="sm">Most popular</c-lb.badge>
{% endif %}
</div>
<p class="text-sm text-base-content/60">{{ plan.lede }}</p>
<div class="flex items-baseline gap-1">
<span class="text-2xl font-semibold text-base-content/70">$</span>
<span class="text-5xl font-bold tracking-tight tabular-nums">{{ plan.monthly }}</span>
<span class="text-sm text-base-content/50">/month</span>
</div>
<p class="text-xs text-base-content/50">
${{ plan.annual }} billed annually, which is two months free.
</p>
{% if plan.featured %}
<c-lb.button variant="primary" modifier="block">{{ plan.cta }}</c-lb.button>
{% else %}
<c-lb.button btnStyle="outline" modifier="block">{{ plan.cta }}</c-lb.button>
{% endif %}
<c-lb.divider class="my-0 text-xs text-base-content/40">Includes</c-lb.divider>
<div class="flex flex-col gap-2.5">
{% for feature in plan.features %}
<div class="flex items-start gap-2 text-sm">
<c-lbi
n="rmx.checkbox-circle"
w="18"
h="18"
class="shrink-0 mt-0.5 {% if plan.featured %}text-primary{% else %}text-success{% endif %}"
/>
<span>{{ feature }}</span>
</div>
{% endfor %}
</div>
</c-lb.card.body>
</c-lb.card>
Learn from this block
-
One loop over three plans, then the proof strip. All the card markup lives in the tier component, so the page stays readable at a glance.
-
The middle plan is lifted with border, elevation and a `primary` ring — every cue a theme token, so it recolours with the theme instead of fighting it. The cards stay the same size; only fill and border say which one is featured.
-
Nothing on this page is reactive, so nothing loads Datastar. labb only ships the runtime when a `c-lbr.*` component or a `$`-prefixed prop asks for it — which is why a static pricing page here weighs what static HTML weighs.
Single plan
One plan, everything included, with an FAQ underneath — a static page that ships zero JavaScript
-
components
-
single_plan
-
-
templates
-
pages
-
<main class="container mx-auto max-w-5xl px-4 py-16 flex flex-col gap-12">
<div class="grid gap-10 lg:grid-cols-2 items-start">
<c-single-plan.pitch />
<c-single-plan.card :plan=plan />
</div>
<c-single-plan.faq :faqs=faqs />
</main>
<c-vars :plan="{}" />
<c-lb.card border class="border-primary border-2 shadow-lg">
<c-lb.card.body class="gap-5">
<div class="flex flex-col gap-1">
<h2 class="text-lg font-semibold">{{ plan.name }}</h2>
<p class="text-sm text-base-content/60">{{ plan.tagline }}</p>
</div>
<div class="flex items-baseline gap-1">
<span class="text-2xl font-semibold text-base-content/70">$</span>
<span class="text-5xl font-bold tracking-tight tabular-nums">{{ plan.monthly }}</span>
<span class="text-sm text-base-content/50">/month</span>
</div>
<p class="text-xs text-base-content/50">
Or ${{ plan.annual }} a year, which is two months free. No card for the trial.
</p>
<c-lb.button variant="primary" modifier="block">{{ plan.cta }}</c-lb.button>
<c-lb.divider class="my-0 text-xs text-base-content/40">Everything, included</c-lb.divider>
<div class="grid gap-2.5">
{% for feature in plan.features %}
<div class="flex items-start gap-2 text-sm">
<c-lbi n="rmx.checkbox-circle" w="18" h="18" class="shrink-0 mt-0.5 text-success" />
<span>{{ feature }}</span>
</div>
{% endfor %}
</div>
<div class="flex items-center gap-2 rounded-lg bg-base-200 p-3 text-xs text-base-content/60">
<c-lbi n="rmx.shield-check" w="16" h="16" class="shrink-0 text-primary" />
<span>Cancel any time and take a full export with you.</span>
</div>
</c-lb.card.body>
</c-lb.card>
<c-vars :faqs="[]" />
<div class="flex flex-col gap-6">
<div class="flex flex-col gap-2">
<h2 class="text-2xl font-semibold tracking-tight">Before you ask</h2>
<p class="text-sm text-base-content/60">
The five questions that come up on every call. Still stuck?
<a href="#" class="link link-primary">Email a human</a> — no demo required.
</p>
</div>
<c-lb.accordion join>
{% for faq in faqs %}
<c-lb.accordion.item
name="arden-faq"
style="arrow"
border
:checked=forloop.first
title="{{ faq.q }}"
>
<p class="text-sm text-base-content/70 leading-relaxed">{{ faq.a }}</p>
</c-lb.accordion.item>
{% endfor %}
</c-lb.accordion>
</div>
<div class="flex flex-col gap-8">
<div class="flex flex-col gap-4">
<c-lb.badge style="soft" size="sm" icon="rmx.price-tag-3">One plan, one price</c-lb.badge>
<h1 class="text-4xl font-semibold tracking-tight text-balance">
We only sell one thing
</h1>
<p class="text-base-content/60">
Arden has no starter tier to outgrow and no enterprise tier to be upsold
into. Every workspace gets forecasting, alerts and the full revenue graph on
day one, because a pricing page that hides the useful half is just a sales
call with extra steps.
</p>
</div>
<c-lb.card class="bg-base-200/50">
<c-lb.card.body class="gap-4 p-6">
<p class="text-sm leading-relaxed">
“I have bought revenue tooling three times. This is the first time I did
not need a call to find out what it costs.”
</p>
<div class="flex items-center gap-3">
<c-lb.avatar placeholder initials="MC" bgColor="secondary" size="sm" />
<div class="text-xs">
<div class="font-medium">Mira Chen</div>
<div class="text-base-content/50">Founder, AtlasForge</div>
</div>
</div>
</c-lb.card.body>
</c-lb.card>
<div class="flex flex-col gap-3">
<p class="text-xs uppercase tracking-wider text-base-content/40">
Trusted by 2,400+ finance and ops teams
</p>
<div class="flex flex-wrap gap-x-6 gap-y-2 text-sm font-medium text-base-content/50">
<span>AtlasForge</span>
<span>Kite & Bell</span>
<span>Northwind Co</span>
<span>Verity Labs</span>
</div>
</div>
</div>
Learn from this block
-
Three components and a grid. The pitch, the plan and the FAQ each own their own markup, so the page reads as what it is rather than as a wall of divs.
-
The FAQ opens and closes with no script on the page. Nothing in this block loads Datastar, because nothing in it needs to — reactivity in labb is opt-in, so a static pricing page ships as a static pricing page.
-
The highlight is `primary`, not a hex value. Drop this block into any daisyUI theme and the card still looks deliberate — which is the whole reason blocks are forbidden from hardcoding a colour.
Three-tier toggle
Three plans with a monthly/annual toggle — every price re-renders from one client signal, with no server round-trip
-
components
-
tier_toggle
-
-
templates
-
pages
-
<script>
function ardenPeriod(annual) {
return {
annual: annual,
monthlyStyle: annual ? 'ghost' : '',
annualStyle: annual ? '' : 'ghost',
suffix: annual ? '/year' : '/month',
saveVariant: annual ? 'success' : 'neutral',
saveLabel: annual ? 'Saving 2 months' : '2 months free',
note: annual ? 'Billed once a year. Two months on us.' : 'Billed monthly. Cancel any time.'
};
}
</script>
<c-lbr.signals id="pricing-period" :$period=period />
<main class="container mx-auto max-w-6xl px-4 py-16 flex flex-col gap-12">
<c-tier-toggle.header />
<div class="grid gap-6 lg:grid-cols-3 items-stretch">
{% for plan in plans %}
<c-tier-toggle.tier :plan=plan />
{% endfor %}
</div>
<c-tier-toggle.assurance />
<c-tier-toggle.trust />
</main>
<div class="grid gap-6 md:grid-cols-3">
<c-lb.card class="bg-base-200/50">
<c-lb.card.body class="gap-2 p-5">
<c-lbi n="rmx.shield-check" w="20" h="20" class="text-primary" />
<h3 class="text-sm font-semibold">Switch plans mid-cycle</h3>
<p class="text-sm text-base-content/60">
Upgrades are prorated to the day. Downgrades take effect at renewal, so
nothing you have already paid for disappears.
</p>
</c-lb.card.body>
</c-lb.card>
<c-lb.card class="bg-base-200/50">
<c-lb.card.body class="gap-2 p-5">
<c-lbi n="rmx.database-2" w="20" h="20" class="text-primary" />
<h3 class="text-sm font-semibold">Your data leaves with you</h3>
<p class="text-sm text-base-content/60">
Full CSV and API export on every plan, including the free trial. No
retention hold, no export fee.
</p>
</c-lb.card.body>
</c-lb.card>
<c-lb.card class="bg-base-200/50">
<c-lb.card.body class="gap-2 p-5">
<c-lbi n="rmx.time" w="20" h="20" class="text-primary" />
<h3 class="text-sm font-semibold">14 days, no card</h3>
<p class="text-sm text-base-content/60">
Connect Stripe and Arden backfills 24 months of revenue history in about
four minutes. Decide after you have seen your own numbers.
</p>
</c-lb.card.body>
</c-lb.card>
</div>
<c-vars :included="True" />
<div class="flex items-start gap-2 text-sm {% if not included %}opacity-40{% endif %}">
<c-lbi
n="{% if included %}rmx.checkbox-circle{% else %}rmx.close-circle{% endif %}"
w="18"
h="18"
class="shrink-0 mt-0.5 {% if included %}text-success{% else %}text-base-content/40{% endif %}"
/>
<span>{{ slot }}</span>
</div>
<div class="flex flex-col items-center gap-5 text-center">
<c-lb.badge style="soft" size="sm" icon="rmx.line-chart">Arden pricing</c-lb.badge>
<h1 class="text-4xl sm:text-5xl font-semibold tracking-tight text-balance">
Pricing that follows your revenue
</h1>
<p class="max-w-xl text-base-content/60">
Every plan includes the full revenue graph — customers, invoices, renewals and
events. You are only ever paying for the seats and the volume you actually use.
</p>
<c-lb.join class="mt-2 p-1 bg-base-200 rounded-lg">
<c-lb.button
data-lbb-start
type="button"
class="join-item"
size="sm"
variant="primary"
btnStyle="$period.monthlyStyle:"
data-on:click="$period = ardenPeriod(false)"
>Monthly</c-lb.button>
<c-lb.button
type="button"
class="join-item"
size="sm"
variant="primary"
btnStyle="$period.annualStyle:ghost"
data-on:click="$period = ardenPeriod(true)"
>Annual</c-lb.button>
</c-lb.join>
<c-lb.badge
id="period-note"
size="sm"
style="soft"
variant="$period.saveVariant:neutral"
data-text="$period.saveLabel"
>2 months free</c-lb.badge>
</div>
<c-vars :plan="{}" />
<c-lb.card
border
class="h-full {% if plan.featured %}border-primary border-2 shadow-lg{% endif %}"
>
<c-lb.card.body class="gap-5">
<div class="flex items-start justify-between gap-3">
<div class="flex flex-col gap-1">
<h2 class="text-lg font-semibold">{{ plan.name }}</h2>
<p class="text-sm text-base-content/60 max-w-[22ch]">{{ plan.tagline }}</p>
</div>
{% if plan.featured %}
<c-lb.badge variant="primary" size="sm">Most popular</c-lb.badge>
{% endif %}
</div>
<div class="flex items-baseline gap-1">
<span class="text-2xl font-semibold text-base-content/70">$</span>
<span
id="price-{{ plan.name|lower }}"
class="text-5xl font-bold tracking-tight tabular-nums"
data-text="$period.annual ? '{{ plan.annual }}' : '{{ plan.monthly }}'"
>{{ plan.monthly }}</span>
<span
class="text-sm text-base-content/50"
data-text="$period.suffix"
>/month</span>
</div>
<p class="text-xs text-base-content/50" data-text="$period.note">
Billed monthly. Cancel any time.
</p>
{% if plan.featured %}
<c-lb.button variant="primary" modifier="block">{{ plan.cta }}</c-lb.button>
{% else %}
<c-lb.button btnStyle="outline" modifier="block">{{ plan.cta }}</c-lb.button>
{% endif %}
<c-lb.divider class="my-0 text-xs text-base-content/40">What you get</c-lb.divider>
<div class="flex flex-col gap-2.5">
{% for feature in plan.features %}
<c-tier-toggle.feature>{{ feature }}</c-tier-toggle.feature>
{% endfor %}
{% for feature in plan.excluded %}
<c-tier-toggle.feature :included="False">{{ feature }}</c-tier-toggle.feature>
{% endfor %}
</div>
</c-lb.card.body>
</c-lb.card>
<div class="flex flex-col items-center gap-8 border-t border-base-300 pt-10">
<c-lb.card class="max-w-2xl bg-base-100 border border-base-300 shadow-sm">
<c-lb.card.body class="gap-4 p-6">
<p class="text-base leading-relaxed text-balance">
“We moved from Starter to Growth in the second month and the forecasting
paid for the year in one renewal we would otherwise have missed.”
</p>
<div class="flex items-center gap-3">
<c-lb.avatar placeholder initials="JP" bgColor="secondary" size="sm" />
<div class="text-xs">
<div class="font-medium">Jonah Price</div>
<div class="text-base-content/50">Head of Finance, Kite & Bell</div>
</div>
</div>
</c-lb.card.body>
</c-lb.card>
<div class="flex flex-col items-center gap-3">
<p class="text-xs uppercase tracking-wider text-base-content/40">
Trusted by 2,400+ finance and ops teams
</p>
<div class="flex flex-wrap justify-center gap-x-6 gap-y-2 text-sm font-medium text-base-content/50">
<span>AtlasForge</span>
<span>Kite & Bell</span>
<span>Northwind Co</span>
<span>Verity Labs</span>
<span>Ironvale Group</span>
</div>
</div>
</div>
Learn from this block
-
The whole block runs off one client signal. It is declared here in prop mode — an object literal, no schema and no view behind it.
-
Clicking Annual replaces the period object. That is the entire interaction: no fetch, no request, nothing on the wire.
-
This is the canonical reactive prop. Prefix any prop with `$` and it tracks a signal; the part after the colon is what the server renders, so the page is correct before a single byte of JavaScript runs.
-
Three cards, three prices, one signal. Each price reads the period directly, with the monthly figure rendered server-side as the fallback.
Usage calculator
A seat slider that reprices the plan live from derived signals — the whole calculation runs in the browser, with no server
-
components
-
usage_calc
-
-
templates
-
pages
-
<script>
function ardenMoney(n) {
return n.toLocaleString('en-US');
}
function ardenUsage(seats, annual) {
var n = Math.min(60, Math.max(3, Math.round(Number(seats) || 3)));
var tier = n <= 10
? { plan: 'Starter', platform: 49, variant: 'neutral', included: '1,000 tracked customers' }
: n <= 30
? { plan: 'Growth', platform: 149, variant: 'primary', included: '10,000 tracked customers' }
: { plan: 'Scale', platform: 449, variant: 'secondary', included: 'Unlimited tracked customers' };
var months = annual ? 10 : 1;
var seatCost = n * 9;
return {
seats: n,
annual: annual,
plan: tier.plan,
planVariant: tier.variant,
included: tier.included,
platform: ardenMoney(tier.platform * months),
seatCost: ardenMoney(seatCost * months),
total: ardenMoney((tier.platform + seatCost) * months),
suffix: annual ? '/year' : '/month',
monthlyStyle: annual ? 'ghost' : '',
annualStyle: annual ? '' : 'ghost',
note: annual
? 'Billed once a year. Two months on us.'
: 'Billed monthly. Cancel any time.'
};
}
</script>
<c-lbr.signals id="usage-signals" :$usage=usage />
<main class="container mx-auto max-w-5xl px-4 py-16 flex flex-col gap-12">
<c-usage-calc.header />
<div class="grid gap-6 lg:grid-cols-5 items-start">
<div class="lg:col-span-3">
<c-usage-calc.slider />
</div>
<div class="lg:col-span-2">
<c-usage-calc.quote />
</div>
</div>
<c-usage-calc.reassurance />
</main>
<div class="flex flex-col gap-4 max-w-2xl">
<c-lb.badge style="soft" size="sm" icon="rmx.calculator">Work out your bill</c-lb.badge>
<h1 class="text-4xl font-semibold tracking-tight text-balance">
Move the slider. That is the price.
</h1>
<p class="text-base-content/60">
Arden charges a platform fee for the plan your volume lands in, plus $9 a month
for every named seat. Nothing is metered after the fact and there is no
onboarding fee, so the number below is the number on the invoice.
</p>
</div>
<div class="flex items-start gap-2 text-sm text-base-content/70">
<c-lbi n="rmx.checkbox-circle" w="16" h="16" class="shrink-0 mt-0.5 text-success" />
<span>{{ slot }}</span>
</div>
<div class="flex flex-col gap-6">
<c-lb.card class="bg-base-200/50">
<c-lb.card.body class="gap-3 p-5">
<h2 class="text-sm font-semibold">Included at every size</h2>
<c-usage-calc.line>Full revenue graph: customers, invoices, renewals</c-usage-calc.line>
<c-usage-calc.line>Stripe and Chargebee sync, backfilled on connect</c-usage-calc.line>
<c-usage-calc.line>
<span data-text="$usage.included">10,000 tracked customers</span>
</c-usage-calc.line>
<c-usage-calc.line>Unlimited read-only viewers</c-usage-calc.line>
<c-usage-calc.line>CSV and API export, always</c-usage-calc.line>
</c-lb.card.body>
</c-lb.card>
<c-lb.card class="border border-base-300">
<c-lb.card.body class="gap-4 p-5">
<p class="text-sm leading-relaxed">
“We sized ourselves on this slider, signed the same day, and the first
invoice matched to the dollar.”
</p>
<div class="flex items-center gap-3">
<c-lb.avatar placeholder initials="RO" bgColor="accent" size="sm" />
<div class="text-xs">
<div class="font-medium">Rae Okonjo</div>
<div class="text-base-content/50">COO, Verity Labs</div>
</div>
</div>
</c-lb.card.body>
</c-lb.card>
</div>
<div class="flex flex-col gap-6 border-t border-base-300 pt-8">
<div class="grid gap-6 md:grid-cols-3">
<div class="flex flex-col gap-1">
<span class="text-2xl font-bold tabular-nums">4 min</span>
<span class="text-sm text-base-content/60">
From connecting Stripe to a populated dashboard, median across new
workspaces.
</span>
</div>
<div class="flex flex-col gap-1">
<span class="text-2xl font-bold tabular-nums">2,400+</span>
<span class="text-sm text-base-content/60">
Finance and ops teams running their board numbers out of Arden.
</span>
</div>
<div class="flex flex-col gap-1">
<span class="text-2xl font-bold tabular-nums">0</span>
<span class="text-sm text-base-content/60">
Setup fees, seat minimums and annual lock-ins. Leave whenever you like.
</span>
</div>
</div>
<c-lb.alert alertStyle="soft" icon="rmx.team">
<span>
Past 60 seats or running several workspaces? That is an Enterprise
conversation — we will quote a flat platform fee and drop the per-seat line
entirely.
</span>
</c-lb.alert>
</div>
<c-lb.card border class="bg-base-100">
<c-lb.card.body class="gap-6">
<div class="flex items-end justify-between gap-4">
<div class="flex flex-col gap-1">
<label class="text-sm font-medium" for="seat-count">
How many people need an Arden seat?
</label>
<p class="text-xs text-base-content/50">
Read-only viewers are free on every plan.
</p>
</div>
<div class="flex items-baseline gap-1.5 shrink-0">
<span
id="seat-count-value"
class="text-3xl font-bold tabular-nums"
data-text="$usage.seats"
>12</span>
<span class="text-sm text-base-content/50">seats</span>
</div>
</div>
<div class="flex flex-col gap-2">
<c-lb.range
id="seat-count"
variant="primary"
min="3"
max="60"
step="1"
value="12"
class="w-full"
data-lbb-start
data-on:input="$usage = ardenUsage(el.value, $usage.annual)"
/>
<div class="flex justify-between text-xs text-base-content/40">
<span>3</span>
<span>60</span>
</div>
</div>
<c-lb.divider class="my-0" />
<div class="flex flex-col gap-3">
<div class="flex items-center justify-between gap-3">
<span class="text-sm text-base-content/70">Recommended plan</span>
<c-lb.badge
id="recommended-plan"
size="sm"
style="soft"
variant="$usage.planVariant:primary"
data-text="$usage.plan"
>Growth</c-lb.badge>
</div>
<div class="flex items-center justify-between gap-3 text-sm">
<span class="text-base-content/70">
<span data-text="$usage.plan">Growth</span> platform fee
</span>
<span class="tabular-nums font-medium">
$<span data-text="$usage.platform">149</span>
</span>
</div>
<div class="flex items-center justify-between gap-3 text-sm">
<span class="text-base-content/70">
<span data-text="$usage.seats">12</span> seats × $9
</span>
<span class="tabular-nums font-medium">
$<span data-text="$usage.seatCost">108</span>
</span>
</div>
<div class="flex items-center justify-between gap-3 border-t border-base-300 pt-3">
<div class="flex flex-col">
<span class="text-sm font-semibold">Your total</span>
<span class="text-xs text-base-content/50" data-text="$usage.note">
Billed monthly. Cancel any time.
</span>
</div>
<div class="flex items-baseline gap-1">
<span class="text-xl font-semibold text-base-content/70">$</span>
<span
id="usage-total"
class="text-4xl font-bold tabular-nums"
data-text="$usage.total"
>257</span>
<span class="text-sm text-base-content/50" data-text="$usage.suffix">/month</span>
</div>
</div>
</div>
<c-lb.join class="self-end p-1 bg-base-200 rounded-lg">
<c-lb.button
type="button"
class="join-item"
size="xs"
variant="primary"
btnStyle="$usage.monthlyStyle:"
data-on:click="$usage = ardenUsage($usage.seats, false)"
>Monthly</c-lb.button>
<c-lb.button
type="button"
class="join-item"
size="xs"
variant="primary"
btnStyle="$usage.annualStyle:ghost"
data-on:click="$usage = ardenUsage($usage.seats, true)"
>Annual</c-lb.button>
</c-lb.join>
</c-lb.card.body>
</c-lb.card>
Learn from this block
-
The signal is the whole quote: seats, plan, the two line items and the total. It arrives as an object in prop mode, so the page renders a correct quote server-side before any JavaScript runs.
-
Every drag step replaces the object with a freshly derived one. The pricing rule lives in one small function above, which keeps the handler a single call — and keeps the network tab empty, because there is no server in this block at all.
-
The canonical reactive prop. `$usage.planVariant` picks the badge's colour as the recommended plan changes under the slider; `primary` after the colon is the server-rendered fallback.
-
Platform fee, seat cost, total, period, plan name — all reading one signal, all updating together. This is opt-in reactivity: one interactive widget on an otherwise static page, and no endpoint behind it.