Tessera
A light, detailed SaaS landing page for a made-up finance workspace — gold light pooling on cream, the product standing in it as a stack of real surfaces, and a four-part tour of it.
A whole landing page — nav, hero, a product tour, six capabilities, a customer quote, pricing, FAQ, close and footer — in a light register: Iris's Amber Glow pools warm gold behind the hero with its reading guard on the copy, and the product stands in it as a stack of real surfaces — a balance with its ninety days, a card, a paid invoice. The same gold rhymes through the page: the card's tile, the forecast line, the list marks, the close. Depth is layering — white surfaces on cream, a lit top edge, two shadows, one near and one far — and hierarchy is three strengths of one ink; money is set in tabular figures.
The detail is in the product, not the ornament: the tour switches between four working surfaces — accounts, cards, invoices, the month-end close — as accessible tabs (the page's one client component); each capability is drawn as its own small piece of UI; pricing switches monthly and annual with no script. Self-contained: its colours are a few variables scoped to .tessera, and it takes your site's typeface. The customer quote is placeholder copy — replace it with a real one or remove it — and a finance product should say plainly who holds the money; add that before it ships.
Details
- Kind
- Landing
- Stack
- React · TypeScript
- Depends on
- Nothing
- Licence
- Free
- Added
- 28 Sep 2026
- Tags
- saas, landing-page, light, fintech, product-tour, pricing, faq, webgl-hero
Its light
- 6%
- 5%
- 12%
- 53%
- 24%
Code
Install
No installation needed — self-contained, paste-in code.
Usage
import { TesseraLanding } from "./tessera/TesseraLanding";
// The whole page — drop it into a route and replace the copy.
export default function Page() {
return <TesseraLanding />;
}Component
The real source, exactly as it ships — multiple files, kept together.
import type { ReactNode } from "react";
import { AmberGlowField } from "@/components/iris/visuals/backgrounds/AmberGlowField";
import { TesseraTour } from "./TesseraTour";
import { Avatar, Chip, Forecast, Mark, Money, Spark } from "./parts";
import "./tessera.css";
/**
* Tessera — a light SaaS landing page, from Iris's Templates.
*
* A whole page for a (made-up) finance workspace. Its one light is gold:
* Iris's `AmberGlowField` pools warm light on a cream ground behind the
* hero, the product stands in it as a stack of real surfaces — a balance,
* a card, a paid invoice — and the same gold rhymes through the page: the
* card's tile, the forecast line, the close. Depth is layering, not
* decoration; hierarchy is three strengths of one ink.
*
* Detail lives in the product, not in ornament: a tour of four real
* surfaces (`TesseraTour`, the page's one client component), six
* capabilities each drawn as its own piece of UI, pricing that switches
* monthly/annual with no script, a quote, the FAQ. The quote is
* placeholder copy — replace it with a real customer's, or remove it.
*/
const NAV = [
{ label: "Product", href: "#tour" },
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "#pricing" },
{ label: "FAQ", href: "#faq" },
];
function Label({ children }: { children: ReactNode }) {
return <p className="text-[0.8125rem] font-medium text-[color:var(--ts-gold)]">{children}</p>;
}
function Title({ id, children, className = "" }: { id?: string; children: ReactNode; className?: string }) {
return (
<h2 id={id} className={`mt-3 text-[clamp(2rem,1.3rem+2.4vw,3.25rem)] leading-[1.04] font-semibold tracking-[-0.035em] text-balance ${className}`}>
{children}
</h2>
);
}
/* ---- nav ------------------------------------------------------------ */
function Nav() {
return (
<header className="ts-nav sticky top-0 z-30 border-b border-[color:var(--ts-line)]">
<nav aria-label="Main" className="mx-auto flex h-16 max-w-7xl items-center justify-between px-5 sm:px-8">
<a href="#top" className="flex items-center gap-2.5 text-[1.0625rem] font-semibold tracking-[-0.01em]">
<Mark />
Tessera
</a>
<ul className="hidden items-center gap-8 text-[0.9375rem] text-[color:var(--ts-dim)] md:flex">
{NAV.map((n) => (
<li key={n.href}>
<a href={n.href} className="transition-colors duration-150 hover:text-[color:var(--ts-fg)]">
{n.label}
</a>
</li>
))}
</ul>
<div className="hidden items-center gap-5 md:flex">
<a href="#" className="text-[0.9375rem] text-[color:var(--ts-dim)] transition-colors duration-150 hover:text-[color:var(--ts-fg)]">
Log in
</a>
<a href="#pricing" className="ts-primary rounded-full px-4 py-2 text-[0.875rem] font-medium">
Open an account
</a>
</div>
<details className="relative md:hidden">
<summary className="flex size-10 cursor-pointer items-center justify-center rounded-full" aria-label="Menu">
<svg viewBox="0 0 24 24" aria-hidden="true" className="size-5">
<path d="M4 8h16M4 16h16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" />
</svg>
</summary>
<div className="ts-surface absolute right-0 mt-2 w-60 rounded-2xl p-2">
{NAV.map((n) => (
<a key={n.href} href={n.href} className="block rounded-xl px-3 py-2.5 text-[0.9375rem] text-[color:var(--ts-dim)] hover:text-[color:var(--ts-fg)]">
{n.label}
</a>
))}
<a href="#pricing" className="ts-primary mt-2 block rounded-xl px-3 py-2.5 text-center text-[0.9375rem] font-medium">
Open an account
</a>
</div>
</details>
</nav>
</header>
);
}
/* ---- hero ------------------------------------------------------------ */
const NINETY_DAYS = [1.62, 1.66, 1.64, 1.71, 1.78, 1.74, 1.82, 1.9, 1.86, 1.95, 2.02, 1.98, 2.1, 2.18, 2.14, 2.26, 2.31, 2.28, 2.36, 2.48];
function ProductStack() {
return (
<div className="relative mx-auto w-full max-w-[34rem] lg:mx-0">
{/* Back: the balance across every account. */}
<div className="ts-surface rounded-3xl p-6 pb-10">
<div className="flex items-center justify-between">
<p className="text-[0.8125rem] text-[color:var(--ts-faint)]">Cash · all accounts</p>
<Chip tone="green">+4.2% this month</Chip>
</div>
<p className="mt-2 text-[clamp(1.75rem,1.4rem+1.4vw,2.25rem)] font-semibold tracking-[-0.03em]">
<Money value={2480193.62} />
</p>
<Spark points={NINETY_DAYS} className="mt-4 h-16 w-full" />
<ul className="mt-5 flex flex-col divide-y divide-[color:var(--ts-line)] text-[0.875rem]">
{[
["Operating", "4821", 1204118.4],
["Payroll", "0913", 640075.22],
["Reserve", "7730", 636000.0],
].map(([name, last, amt]) => (
<li key={name as string} className="flex items-center justify-between py-2.5">
<span>
{name} <span className="text-[color:var(--ts-faint)]">••{last}</span>
</span>
<Money value={amt as number} className="text-[color:var(--ts-dim)]" />
</li>
))}
</ul>
</div>
{/* Front: a card issued a minute ago, and an invoice matched on
arrival — pulled up by exactly the balance's bottom padding, so
they stand on its edge and never over a row of it. */}
{/* On a phone the invoice takes its own line under the card. */}
<div className="relative -mt-10 -mr-[3%] -ml-[4%] flex flex-wrap items-end justify-between gap-x-4 gap-y-3 sm:-mr-[6%] sm:-ml-[8%] sm:flex-nowrap">
<div className="ts-lifted flex aspect-[1.586] w-[46%] shrink-0 flex-col justify-between rounded-2xl bg-[color:var(--ts-fg)] p-4 text-[color:var(--ts-ink)]">
<div className="flex items-start justify-between">
<span className="text-[0.75rem] font-semibold">Tessera</span>
<span aria-hidden="true" className="size-4 rounded-[5px] bg-[color:var(--ts-gold-fill)]" />
</div>
<div>
<p className="font-mono text-[0.75rem] tracking-[0.12em] opacity-80">•••• 2231</p>
<p className="mt-0.5 text-[0.6875rem] opacity-70">Maya Lin · $5,000 / mo</p>
</div>
</div>
<div className="ts-lifted min-w-0 flex-1 basis-full rounded-2xl bg-[color:var(--ts-surface)] p-4 sm:mb-5 sm:basis-0">
<div className="flex items-center gap-3">
<span aria-hidden="true" className="grid grid-cols-1 size-8 shrink-0 place-items-center rounded-full bg-[color:var(--ts-green-soft)] text-[color:var(--ts-green)]">
<svg viewBox="0 0 16 16" className="size-4">
<path d="m3.5 8.5 3 3 6-7" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
<div className="min-w-0">
<p className="truncate text-[0.8125rem] font-semibold">INV-1042 paid</p>
<p className="truncate text-[0.75rem] text-[color:var(--ts-faint)]">Northwind Studio · matched</p>
</div>
<Money value={12400} className="ml-auto shrink-0 text-[0.875rem] font-semibold" />
</div>
</div>
</div>
</div>
);
}
function Hero() {
return (
<section id="top" aria-labelledby="hero-title" className="relative isolate overflow-hidden">
<div aria-hidden="true" className="absolute inset-0 -z-10">
<AmberGlowField guardSelector="#tessera-hero-copy" />
</div>
<div className="mx-auto grid grid-cols-1 max-w-7xl items-center gap-16 px-5 pt-[clamp(4rem,10vh,7rem)] pb-[clamp(4rem,10vh,6rem)] sm:px-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
<div id="tessera-hero-copy" className="max-w-xl">
<a href="#tour" className="group inline-flex items-center gap-2 text-[0.875rem] text-[color:var(--ts-dim)]">
<span className="font-medium text-[color:var(--ts-gold)]">New</span>
Close the month in a day
<span aria-hidden="true" className="transition-transform duration-150 group-hover:translate-x-0.5">
→
</span>
</a>
<h1 id="hero-title" className="mt-6 text-[clamp(2.75rem,1.6rem+4vw,4.75rem)] leading-[0.98] font-semibold tracking-[-0.045em] text-balance">
Every account, card and invoice. One ledger.
</h1>
<p className="mt-6 max-w-[44ch] text-[clamp(1.0625rem,1rem+0.3vw,1.25rem)] leading-[1.55] text-pretty text-[color:var(--ts-dim)]">
Tessera connects your banks, issues your cards and sends your invoices — then reconciles all of it as it
happens, so the month closes in a day, not a week.
</p>
<div className="mt-9 flex flex-wrap items-center gap-x-6 gap-y-3">
<a href="#pricing" className="ts-primary rounded-full px-6 py-3 text-[0.9375rem] font-medium">
Open an account
</a>
<a href="#tour" className="group inline-flex items-center gap-1.5 text-[0.9375rem] font-medium">
Take the tour
<span aria-hidden="true" className="text-[color:var(--ts-faint)] transition-transform duration-150 group-hover:translate-x-0.5">
→
</span>
</a>
</div>
<p className="mt-8 text-[0.875rem] text-[color:var(--ts-faint)]">Free to start · set up in ten minutes · no card required</p>
</div>
<ProductStack />
</div>
</section>
);
}
/* ---- tour ------------------------------------------------------------ */
function Tour() {
return (
<section id="tour" aria-labelledby="tour-title" className="scroll-mt-20 border-t border-[color:var(--ts-line)]">
<div className="mx-auto max-w-7xl px-5 py-[clamp(6rem,13vw,10rem)] sm:px-8">
<div className="max-w-2xl">
<Label>The product</Label>
<Title id="tour-title">One place for the money moving through your company.</Title>
</div>
<div className="mt-12">
<TesseraTour />
</div>
</div>
</section>
);
}
/* ---- features -------------------------------------------------------- */
function Cell({ title, body, children }: { title: string; body: string; children: ReactNode }) {
return (
<li className="flex flex-col rounded-3xl bg-[color:var(--ts-surface-2)] p-6 shadow-[inset_0_0_0_1px_var(--ts-line)] sm:p-7">
<div className="flex min-h-[10.5rem] items-center justify-center" aria-hidden="true">
{children}
</div>
<h3 className="mt-6 text-[1.0625rem] font-semibold tracking-[-0.01em]">{title}</h3>
<p className="mt-1.5 text-[0.9375rem] leading-[1.6] text-[color:var(--ts-dim)]">{body}</p>
</li>
);
}
function Features() {
return (
<section id="features" aria-labelledby="features-title" className="scroll-mt-20 border-t border-[color:var(--ts-line)]">
<div className="mx-auto max-w-7xl px-5 py-[clamp(6rem,13vw,10rem)] sm:px-8">
<div className="max-w-2xl">
<Label>Built in</Label>
<Title id="features-title">The controls a finance team would set up, already set up.</Title>
</div>
<ul className="mt-14 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
<Cell title="Approvals" body="Spend over a threshold asks the right person first, from wherever they are.">
<div className="ts-surface w-full max-w-[15rem] rounded-2xl p-4">
<div className="flex items-center gap-2.5">
<Avatar name="Omar Haddad" />
<p className="text-[0.8125rem]">
<span className="font-medium">Omar</span> <span className="text-[color:var(--ts-dim)]">requests</span>
</p>
</div>
<p className="mt-3 flex items-baseline justify-between text-[0.875rem]">
<span>Design tool seats</span>
<Money value={540} className="font-semibold" />
</p>
<div className="mt-3 grid grid-cols-2 gap-2 text-[0.75rem] font-medium">
<span className="rounded-lg py-1.5 text-center shadow-[inset_0_0_0_1px_var(--ts-line-strong)]">Decline</span>
<span className="rounded-lg bg-[color:var(--ts-fg)] py-1.5 text-center text-[color:var(--ts-ink)]">Approve</span>
</div>
</div>
</Cell>
<Cell title="Receipts that find their spend" body="Snap it, forward it or let the email arrive — it's matched to the right transaction.">
<div className="relative">
<div className="ts-surface w-40 rotate-[-4deg] rounded-xl p-3 text-[0.6875rem] text-[color:var(--ts-faint)]">
<p className="font-semibold text-[color:var(--ts-fg)]">Umber Coffee</p>
<div className="mt-2 space-y-1">
<p className="flex justify-between"><span>2 × flat white</span><span className="tabular-nums">9.00</span></p>
<p className="flex justify-between"><span>Pastry</span><span className="tabular-nums">4.50</span></p>
<p className="flex justify-between border-t border-dashed border-[color:var(--ts-line-strong)] pt-1 font-semibold text-[color:var(--ts-fg)]"><span>Total</span><span className="tabular-nums">13.50</span></p>
</div>
</div>
<span className="absolute -right-10 -bottom-3">
<Chip tone="green">Matched</Chip>
</span>
</div>
</Cell>
<Cell title="A forecast you can read" body="Runway from what's actually in the bank and what's actually on the way.">
<div className="w-full max-w-[16rem]">
<p className="flex items-baseline justify-between text-[0.8125rem]">
<span className="text-[color:var(--ts-dim)]">Runway</span>
<span className="text-[1.125rem] font-semibold">26 months</span>
</p>
<Forecast past={[3.1, 2.9, 3.0, 2.8, 2.7, 2.72, 2.6]} ahead={[2.55, 2.5, 2.46, 2.4, 2.38]} className="mt-3 h-20 w-full" />
</div>
</Cell>
<Cell title="More than one company" body="Run each entity on its own books and see them together in one balance.">
<div className="flex w-full max-w-[15rem] flex-col gap-2 text-[0.8125rem]">
{[
["Tessera Inc.", "US", 1860000],
["Tessera Ltd", "UK", 420193.62],
["Tessera GmbH", "DE", 200000],
].map(([n, c, v]) => (
<div key={n as string} className="ts-surface flex items-center justify-between rounded-xl px-3 py-2">
<span>
{n} <span className="text-[color:var(--ts-faint)]">{c}</span>
</span>
<Money value={v as number} className="text-[color:var(--ts-dim)]" />
</div>
))}
</div>
</Cell>
<Cell title="Permissions by role" body="Give your bookkeeper the books, your team their cards, and nobody the keys by accident.">
<ul className="ts-surface w-full max-w-[15rem] divide-y divide-[color:var(--ts-line)] rounded-2xl text-[0.8125rem]">
{[
["Owner", "Everything"],
["Bookkeeper", "Books, read-only bank"],
["Employee", "Their own card"],
].map(([role, can]) => (
<li key={role} className="flex items-center justify-between gap-3 px-4 py-2.5">
<span className="font-medium">{role}</span>
<span className="text-right text-[color:var(--ts-faint)]">{can}</span>
</li>
))}
</ul>
</Cell>
<Cell title="Plays well with your stack" body="Sync to your accounting system, your payroll and the spreadsheet you won't give up.">
<div className="flex max-w-[15rem] flex-wrap justify-center gap-2">
{["Accounting", "Payroll", "HR", "CRM", "Spreadsheets", "Webhooks"].map((t) => (
<Chip key={t}>{t}</Chip>
))}
</div>
</Cell>
</ul>
</div>
</section>
);
}
/* ---- a word from a customer (placeholder) ---------------------------- */
function Quote() {
return (
<section aria-label="What a customer says" className="border-t border-[color:var(--ts-line)]">
<figure className="mx-auto max-w-4xl px-5 py-[clamp(6rem,13vw,10rem)] text-center sm:px-8">
<Mark className="mx-auto size-8" />
<blockquote className="mt-8 text-[clamp(1.5rem,1.1rem+1.6vw,2.25rem)] leading-[1.3] font-medium tracking-[-0.02em] text-balance">
“We closed June on the second of July. It used to take us until the twentieth — and three people who
had better things to do.”
</blockquote>
<figcaption className="mt-8 flex items-center justify-center gap-3 text-[0.9375rem]">
<Avatar name="Priya Raman" className="size-9" />
<span className="text-left">
<span className="block font-medium">Priya Raman</span>
<span className="block text-[0.8125rem] text-[color:var(--ts-faint)]">Head of Finance, Loom & Loft</span>
</span>
</figcaption>
</figure>
</section>
);
}
/* ---- pricing --------------------------------------------------------- */
const PLANS = [
{
name: "Starter",
blurb: "For a company of a few, getting organised.",
monthly: "$0",
annual: "$0",
per: "forever",
points: ["Business account", "Up to 5 cards", "Invoices and reminders", "Bank feeds and rules"],
cta: "Open an account",
},
{
name: "Growth",
blurb: "For a team with a real month end.",
monthly: "$49",
annual: "$39",
per: "per month",
points: ["Everything in Starter", "Unlimited cards and policies", "Approvals and receipts", "Month-end close", "Accounting sync"],
cta: "Start a 30-day trial",
featured: true,
},
{
name: "Scale",
blurb: "For several entities and an audit.",
monthly: "Custom",
annual: "Custom",
per: "",
points: ["Everything in Growth", "Multiple entities", "Custom roles", "Dedicated support"],
cta: "Talk to us",
},
];
function Pricing() {
return (
<section id="pricing" aria-labelledby="pricing-title" className="scroll-mt-20 border-t border-[color:var(--ts-line)]">
<div className="mx-auto max-w-7xl px-5 py-[clamp(6rem,13vw,10rem)] sm:px-8">
<div className="flex flex-wrap items-end justify-between gap-8">
<div className="max-w-2xl">
<Label>Pricing</Label>
<Title id="pricing-title">Free to start. Priced by what you use, not who you hire.</Title>
</div>
<fieldset className="ts-billing inline-flex rounded-full bg-[color:var(--ts-surface-2)] p-1 text-[0.875rem] font-medium text-[color:var(--ts-dim)] shadow-[inset_0_0_0_1px_var(--ts-line)]">
<legend className="sr-only">Billing</legend>
<label className="cursor-pointer rounded-full px-4 py-2">
<input type="radio" name="tessera-billing" value="monthly" defaultChecked className="sr-only" />
Monthly
</label>
<label className="cursor-pointer rounded-full px-4 py-2">
<input type="radio" name="tessera-billing" value="annual" className="sr-only" />
Annual <span className="text-[color:var(--ts-gold)]">−20%</span>
</label>
</fieldset>
</div>
<ul className="mt-14 grid grid-cols-1 gap-5 lg:grid-cols-3">
{PLANS.map((p) => (
<li
key={p.name}
className={`flex flex-col rounded-3xl p-7 sm:p-8 ${p.featured ? "ts-lifted bg-[color:var(--ts-surface)]" : "shadow-[inset_0_0_0_1px_var(--ts-line)]"}`}
>
<div className="flex items-center justify-between">
<h3 className="text-[1.0625rem] font-semibold">{p.name}</h3>
{p.featured && <Chip tone="gold">Most teams</Chip>}
</div>
<p className="mt-2 text-[0.9375rem] text-[color:var(--ts-dim)]">{p.blurb}</p>
<p className="mt-6 flex items-baseline gap-2">
<span className="text-[2.75rem] leading-none font-semibold tracking-[-0.04em] tabular-nums">
<span data-billing="monthly">{p.monthly}</span>
<span data-billing="annual">{p.annual}</span>
</span>
{p.per && <span className="text-[0.875rem] text-[color:var(--ts-faint)]">{p.per}</span>}
</p>
<ul className="mt-8 flex flex-col gap-3 border-t border-[color:var(--ts-line)] pt-7 text-[0.9375rem]">
{p.points.map((pt) => (
<li key={pt} className="flex items-center gap-3">
<span aria-hidden="true" className="size-1.5 rounded-[2px] bg-[color:var(--ts-gold-fill)]" />
{pt}
</li>
))}
</ul>
<div className="mt-auto pt-10">
<a
href="#"
className={`block rounded-full px-5 py-3 text-center text-[0.9375rem] font-medium ${
p.featured ? "ts-primary" : "shadow-[inset_0_0_0_1px_var(--ts-line-strong)] transition-colors duration-150 hover:bg-[color:var(--ts-surface)]"
}`}
>
{p.cta}
</a>
</div>
</li>
))}
</ul>
</div>
</section>
);
}
/* ---- FAQ -------------------------------------------------------------- */
const FAQ = [
{ q: "Can I keep my current bank?", a: "Yes. Connect the accounts you already have and Tessera reads them; open accounts with us only if you want to." },
{ q: "How long does setup take?", a: "About ten minutes to connect accounts and issue a first card. Rules and approvals can wait until you need them." },
{ q: "Does it replace my accountant?", a: "No — it gives them clean, matched books to work from, and an export in the format they already use." },
{ q: "What happens at month end?", a: "Most of the close is already done. You get a short checklist of what's left, and one click to post it to your ledger." },
{ q: "Can I cancel any time?", a: "Yes. Monthly plans stop at the end of the month; annual plans at the end of the year. Your data exports either way." },
];
function Faq() {
return (
<section id="faq" aria-labelledby="faq-title" className="scroll-mt-20 border-t border-[color:var(--ts-line)]">
<div className="mx-auto grid grid-cols-1 max-w-7xl gap-12 px-5 py-[clamp(6rem,13vw,10rem)] sm:px-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">
<div>
<Label>FAQ</Label>
<Title id="faq-title">The questions finance people ask first.</Title>
</div>
<div className="border-t border-[color:var(--ts-line)]">
{FAQ.map((f) => (
<details key={f.q} className="border-b border-[color:var(--ts-line)]">
<summary className="flex cursor-pointer items-center justify-between gap-6 py-5 text-[1.0625rem] font-medium">
{f.q}
<svg viewBox="0 0 16 16" aria-hidden="true" className="ts-plus size-4 shrink-0 text-[color:var(--ts-faint)]">
<path d="M8 2v12M2 8h12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
</summary>
<p className="max-w-[60ch] pb-6 text-[0.9375rem] leading-[1.65] text-[color:var(--ts-dim)]">{f.a}</p>
</details>
))}
</div>
</div>
</section>
);
}
/* ---- close & footer --------------------------------------------------- */
function Close() {
return (
<section aria-labelledby="close-title" className="ts-glow border-t border-[color:var(--ts-line)]">
<div className="mx-auto max-w-3xl px-5 py-[clamp(7rem,15vw,11rem)] text-center sm:px-8">
<Title id="close-title">Close next month in a day.</Title>
<p className="mx-auto mt-5 max-w-[40ch] text-[1.0625rem] text-[color:var(--ts-dim)]">
Open an account in ten minutes. Bring your banks, your team and your invoices — Tessera does the matching.
</p>
<div className="mt-9 flex flex-wrap items-center justify-center gap-x-6 gap-y-3">
<a href="#pricing" className="ts-primary rounded-full px-6 py-3 text-[0.9375rem] font-medium">
Open an account
</a>
<a href="#" className="text-[0.9375rem] font-medium">
Talk to us
</a>
</div>
</div>
</section>
);
}
const FOOTER = [
{ heading: "Product", links: ["Accounts", "Cards", "Invoices", "Close", "Pricing"] },
{ heading: "Company", links: ["About", "Careers", "Press"] },
{ heading: "Resources", links: ["Guides", "Help centre", "Status"] },
{ heading: "Legal", links: ["Terms", "Privacy", "Security"] },
];
function Footer() {
return (
<footer className="border-t border-[color:var(--ts-line)]">
<div className="mx-auto flex max-w-7xl flex-wrap justify-between gap-12 px-5 py-14 sm:px-8">
<div className="max-w-xs">
<a href="#top" className="flex items-center gap-2.5 font-semibold">
<Mark className="size-5" />
Tessera
</a>
<p className="mt-3 text-[0.875rem] text-[color:var(--ts-faint)]">Money, measured — for companies of a few, and of a few hundred.</p>
</div>
<div className="flex flex-wrap gap-x-16 gap-y-8">
{FOOTER.map((col) => (
<div key={col.heading}>
<p className="text-[0.8125rem] font-medium">{col.heading}</p>
<ul className="mt-3 flex flex-col gap-2 text-[0.875rem] text-[color:var(--ts-faint)]">
{col.links.map((l) => (
<li key={l}>
<a href="#" className="transition-colors duration-150 hover:text-[color:var(--ts-fg)]">
{l}
</a>
</li>
))}
</ul>
</div>
))}
</div>
</div>
<p className="mx-auto max-w-7xl px-5 pb-10 text-[0.8125rem] text-[color:var(--ts-faint)] sm:px-8">© 2026 Tessera</p>
</footer>
);
}
export function TesseraLanding() {
return (
<div className="tessera">
<Nav />
<main>
<Hero />
<Tour />
<Features />
<Quote />
<Pricing />
<Faq />
<Close />
</main>
<Footer />
</div>
);
}
