Blocks / Marketing
Pricing section
Four plans with a monthly or yearly toggle, a line of small print and a pricing FAQ in an accordion.
Pricing
Priced per kitchen, not per person on the pass.
Everyone on the line gets their own login. You pay for the kitchens you run, and the free plan stays free.
Pantry
For a small cafe finding out what it actually uses in a week.
- Included, Kitchens1
- Included, Stock itemsUp to 150
- Included, Counts from sales and deliveries
- Not included, Supplier ordering
- Not included, Waste reports
- Not included, Transfers between sites
- Not included, Roles and API
- Not included, Single sign-on and a named contact
Kitchen
Most kitchensFor one busy kitchen that orders every day. Free for the first 30 days.
- Included, Kitchens1
- Included, Stock itemsUnlimited
- Included, Counts from sales and deliveries
- Included, Supplier ordering
- Included, Waste reports
- Not included, Transfers between sites
- Not included, Roles and API
- Not included, Single sign-on and a named contact
Group
For a restaurant with a bakery, or a few cafes sharing one walk-in.
- Included, KitchensUp to 5
- Included, Stock itemsUnlimited
- Included, Counts from sales and deliveries
- Included, Supplier ordering
- Included, Waste reports
- Included, Transfers between sites
- Included, Roles and API
- Not included, Single sign-on and a named contact
Enterprise
For groups past five sites who need single sign-on and one person to call.
- Included, Kitchens6 or more
- Included, Stock itemsUnlimited
- Included, Counts from sales and deliveries
- Included, Supplier ordering
- Included, Waste reports
- Included, Transfers between sites
- Included, Roles and API
- Included, Single sign-on and a named contact
- Prices exclude VAT, which is shown at checkout.
- Cancel from settings. We keep your data for 90 days.
- Change plan any day, charged by the day.
Questions before you pay
Something else on your mind? Write to Priya and the team at hello@larder.example. A person answers, usually before lunch service.
What counts as a kitchen?
What happens when Pantry hits 150 stock items?
Do I need the scanner and printer to start?
Can I pay yearly and still leave?
Do you charge for staff logins?
Install
Writes the block to components/blocks/pricing-section.tsx and its .css, and every part it uses to components/equip/, with the parts those are built from.
npx https://equip.studio311.app/equip.tgz add block:pricing-sectionBuilt from 6 parts
Notes
- Yearly prices are the yearly total; PricingTable divides by 12 for the headline figure and prints the total under it.
- Every plan button has a fragment href, so the block stays a server component; pass onPlanSelect instead and add "use client".
- The FAQ items share one name, so the browser keeps only one answer open at a time.
- Plans list the same features in the same order, which keeps rows level across the cards.
Source
components/blocks/pricing-section.tsx168 lines
import { Accordion, AccordionItem } from "@/components/equip/accordion";
import { Heading } from "@/components/equip/heading";
import { Icon } from "@/components/equip/icon";
import { Link } from "@/components/equip/link";
import { PricingTable } from "@/components/equip/pricing-table";
import { Text } from "@/components/equip/text";
import "./pricing-section.css";
/*
* Plans, the questions people ask before paying, and the small print said plainly.
* Every CTA has a fragment href, so nothing here passes a function and the block stays on the server.
*/
export default function PricingSection() {
return (
<section className="blk-pricing-section" aria-labelledby="pricing-section-title">
<div className="blk-pricing-section-inner">
<header className="blk-pricing-section-head">
<Text size="s" weight="strong" tone="quiet">
Pricing
</Text>
<Heading level={2} id="pricing-section-title" className="blk-pricing-section-title">
Priced per kitchen, not per person on the pass.
</Heading>
<Text size="l" tone="quiet" className="blk-pricing-section-lede">
Everyone on the line gets their own login. You pay for the kitchens you run, and the free plan stays free.
</Text>
</header>
<PricingTable
currency="GBP"
locale="en-GB"
defaultBilling="monthly"
yearlyNote="Save up to 18%"
headingLevel={3}
plans={[
{
id: "pantry",
name: "Pantry",
description: "For a small cafe finding out what it actually uses in a week.",
price: { monthly: 0, yearly: 0 },
priceNote: "Free for one kitchen, for as long as you like",
features: [
{ label: "Kitchens", included: "1" },
{ label: "Stock items", included: "Up to 150" },
{ label: "Counts from sales and deliveries", included: true },
{ label: "Supplier ordering", included: false },
{ label: "Waste reports", included: false },
{ label: "Transfers between sites", included: false },
{ label: "Roles and API", included: false },
{ label: "Single sign-on and a named contact", included: false },
],
cta: { label: "Start counting", href: "#start-pantry" },
},
{
id: "kitchen",
name: "Kitchen",
description: "For one busy kitchen that orders every day. Free for the first 30 days.",
price: { monthly: 39, yearly: 384 },
features: [
{ label: "Kitchens", included: "1" },
{ label: "Stock items", included: "Unlimited" },
{ label: "Counts from sales and deliveries", included: true },
{ label: "Supplier ordering", included: true },
{ label: "Waste reports", included: true },
{ label: "Transfers between sites", included: false },
{ label: "Roles and API", included: false },
{ label: "Single sign-on and a named contact", included: false },
],
cta: { label: "Start a free trial", href: "#start-kitchen" },
highlighted: true,
highlightLabel: "Most kitchens",
},
{
id: "group",
name: "Group",
description: "For a restaurant with a bakery, or a few cafes sharing one walk-in.",
price: { monthly: 119, yearly: 1188 },
features: [
{ label: "Kitchens", included: "Up to 5" },
{ label: "Stock items", included: "Unlimited" },
{ label: "Counts from sales and deliveries", included: true },
{ label: "Supplier ordering", included: true },
{ label: "Waste reports", included: true },
{ label: "Transfers between sites", included: true },
{ label: "Roles and API", included: true },
{ label: "Single sign-on and a named contact", included: false },
],
cta: { label: "Start a group", href: "#start-group" },
},
{
id: "enterprise",
name: "Enterprise",
description: "For groups past five sites who need single sign-on and one person to call.",
price: null,
priceNote: "Priced by site, from six",
features: [
{ label: "Kitchens", included: "6 or more" },
{ label: "Stock items", included: "Unlimited" },
{ label: "Counts from sales and deliveries", included: true },
{ label: "Supplier ordering", included: true },
{ label: "Waste reports", included: true },
{ label: "Transfers between sites", included: true },
{ label: "Roles and API", included: true },
{ label: "Single sign-on and a named contact", included: true },
],
cta: { label: "Talk to us", href: "#contact-sales" },
},
]}
/>
<ul className="blk-pricing-section-assure" aria-label="The small print">
<li className="blk-pricing-section-assure-item">
<Icon name="receipt" className="blk-pricing-section-assure-icon" />
<Text as="span" size="s" tone="quiet">
Prices exclude VAT, which is shown at checkout.
</Text>
</li>
<li className="blk-pricing-section-assure-item">
<Icon name="archive" className="blk-pricing-section-assure-icon" />
<Text as="span" size="s" tone="quiet">
Cancel from settings. We keep your data for 90 days.
</Text>
</li>
<li className="blk-pricing-section-assure-item">
<Icon name="refresh" className="blk-pricing-section-assure-icon" />
<Text as="span" size="s" tone="quiet">
Change plan any day, charged by the day.
</Text>
</li>
</ul>
<div className="blk-pricing-section-faq">
<div className="blk-pricing-section-faq-head">
<Heading level={3} size="l" id="pricing-section-faq-title">
Questions before you pay
</Heading>
<Text tone="quiet">
Something else on your mind? Write to Priya and the team at{" "}
<Link href="#contact-sales">hello@larder.example</Link>
. A person answers, usually before lunch service.
</Text>
</div>
<Accordion className="blk-pricing-section-accordion">
<AccordionItem name="pricing-section-faq" summary="What counts as a kitchen?" open>
One place where stock is counted and food is cooked or baked. A restaurant with a bakery round the corner
is two kitchens, because the flour lives in different rooms.
</AccordionItem>
<AccordionItem name="pricing-section-faq" summary="What happens when Pantry hits 150 stock items?">
Nothing breaks. Larder keeps counting what you have, and asks you to archive slow lines or move to Kitchen
before you add the 151st.
</AccordionItem>
<AccordionItem name="pricing-section-faq" summary="Do I need the scanner and printer to start?">
No. You can check deliveries in by tapping lines on a phone. The shelf kit only makes it quicker on a
Thursday with six drops before ten.
</AccordionItem>
<AccordionItem name="pricing-section-faq" summary="Can I pay yearly and still leave?">
Yes. Cancel from settings and we refund the months you have not started, less any discount you used.
</AccordionItem>
<AccordionItem name="pricing-section-faq" summary="Do you charge for staff logins?">
Never. Chefs, porters and front of house all get their own login on every plan, so counts are signed by
the person who did them.
</AccordionItem>
</Accordion>
</div>
</div>
</section>
);
}components/blocks/pricing-section.css113 lines
@layer blocks {
.blk-pricing-section {
container: blk-pricing-section / inline-size;
background: var(--eq-bg);
color: var(--eq-ink);
}
.blk-pricing-section-inner {
display: grid;
gap: calc(var(--eq-space-6) * 1.25);
max-width: 76rem;
margin-inline: auto;
padding: calc(var(--eq-space-6) * 1.5) var(--eq-space-4);
}
.blk-pricing-section-head {
display: grid;
justify-items: center;
gap: var(--eq-space-3);
max-width: 40rem;
margin-inline: auto;
text-align: center;
}
.blk-pricing-section-head > * {
margin: 0;
}
.blk-pricing-section-title {
font-size: clamp(1.75rem, 5.5cqi, 3rem);
line-height: 1.06;
letter-spacing: -0.025em;
text-wrap: balance;
}
.blk-pricing-section-lede {
max-width: 34rem;
text-wrap: pretty;
}
/* The small print, set like the foot of a till receipt: a torn dashed edge and short lines. */
.blk-pricing-section-assure {
display: grid;
gap: var(--eq-space-3);
margin: 0;
margin-top: calc(var(--eq-space-6) * -0.5);
padding: var(--eq-space-4) 0 0;
list-style: none;
border-top: 1px dashed var(--eq-line-strong);
}
.blk-pricing-section-assure-item {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: start;
gap: var(--eq-space-2);
margin: 0;
}
.blk-pricing-section-assure-item > p,
.blk-pricing-section-assure-item > span {
margin: 0;
}
.blk-pricing-section-assure-icon {
margin-top: 1px;
color: var(--eq-ink-3);
}
.blk-pricing-section-faq {
display: grid;
gap: var(--eq-space-5);
padding-top: calc(var(--eq-space-6) * 1.25);
border-top: 1px solid var(--eq-line);
}
.blk-pricing-section-faq-head {
display: grid;
align-content: start;
gap: var(--eq-space-3);
max-width: 26rem;
}
.blk-pricing-section-faq-head > * {
margin: 0;
}
.blk-pricing-section-accordion {
min-width: 0;
}
@container blk-pricing-section (width >= 40rem) {
.blk-pricing-section-inner {
padding-inline: var(--eq-space-6);
}
.blk-pricing-section-assure {
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: var(--eq-space-5);
}
}
@container blk-pricing-section (width >= 56rem) {
.blk-pricing-section-inner {
padding-block: calc(var(--eq-space-6) * 2.5);
}
.blk-pricing-section-faq {
grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
gap: calc(var(--eq-space-6) * 1.5);
}
}
}