# Pricing 11

> Sera series — three-tier ledger table with hairline feature rows and inverted highlighted plan.

A shadcn/ui block from the [@nusaiba](https://nusaiba.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/nusaiba/pricing-11).

- Page, with a live preview: https://shadcn.exchange/r/nusaiba/pricing-11
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/nusaiba/pricing-11-light-931694d0a75c4029.png
- Registry item: https://nusaiba.dev/r/base-nova/pricing-11.json
- Categories: pricing
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://nusaiba.dev/r/base-nova/pricing-11.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@nusaiba/foundation`, `button`, `@nusaiba/theme-sera`

## Files

### `registry/blocks/sera/sera-motion.tsx`

```tsx
"use client";

import { useRef, type ReactNode } from "react";
import { AnimatePresence, motion, useInView, useReducedMotion } from "motion/react";
import { motionStagger, motionViewport } from "@/lib/motion-tokens";
import { cn } from "@/lib/utils";

const spring = { type: "spring" as const, duration: 0.3, bounce: 0 };

export function useSeraItemVariants() {
	const reduceMotion = useReducedMotion();

	return reduceMotion
		? { hidden: { opacity: 1 }, visible: { opacity: 1 } }
		: {
				hidden: { opacity: 0, filter: "blur(4px)", y: 12 },
				visible: {
					opacity: 1,
					filter: "blur(0px)",
					y: 0,
					transition: spring,
				},
			};
}

export function SeraStagger({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const ref = useRef<HTMLDivElement>(null);
	const inView = useInView(ref, motionViewport);

	return (
		<motion.div
			animate={inView ? "visible" : "hidden"}
			className={className}
			initial="hidden"
			ref={ref}
			variants={{
				hidden: {},
				visible: {
					transition: { staggerChildren: motionStagger.item, delayChildren: 0.04 },
				},
			}}
		>
			{children}
		</motion.div>
	);
}

export function SeraStaggerItem({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const itemVariants = useSeraItemVariants();

	return (
		<motion.div className={className} variants={itemVariants}>
			{children}
		</motion.div>
	);
}

/** Word reveal — signature text motion for Sera hero/headlines. */
export function SeraRevealWord({
	word,
	index,
	className,
}: {
	word: string;
	index: number;
	className?: string;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<span className="inline-flex overflow-hidden pb-[0.08em]">
			<motion.span
				className={className}
				initial={
					reduceMotion ? false : { opacity: 0, y: "100%", filter: "blur(4px)" }
				}
				transition={{
					...spring,
					delay: reduceMotion ? 0 : 0.08 + index * 0.06,
				}}
				viewport={{ once: true, margin: "-5%" }}
				whileInView={
					reduceMotion ? undefined : { opacity: 1, y: 0, filter: "blur(0px)" }
				}
			>
				{word}
			</motion.span>
		</span>
	);
}

export function SeraWordReveal({
	text,
	className,
}: {
	text: string;
	className?: string;
}) {
	const words = text.split(" ");

	return (
		<span className={cn("flex flex-wrap gap-x-[0.28em]", className)}>
			{words.map((word, index) => (
				<SeraRevealWord index={index} key={`${word}-${index}`} word={word} />
			))}
		</span>
	);
}

/** Subtle ledger cell lift on hover. */
export function SeraHoverLift({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<motion.div
			className={className}
			transition={spring}
			whileHover={reduceMotion ? undefined : { y: -2 }}
		>
			{children}
		</motion.div>
	);
}

/** Monochrome infinite marquee — quotes, wordmarks, rows. */
export function SeraMarquee({
	children,
	className,
	duration = 42,
}: {
	children: ReactNode;
	className?: string;
	duration?: number;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<div
			className={cn(
				"overflow-hidden [mask-image:linear-gradient(to_right,transparent,black_6%,black_94%,transparent)]",
				className,
			)}
		>
			<motion.div
				animate={reduceMotion ? undefined : { x: ["0%", "-50%"] }}
				className="flex w-max"
				transition={{ duration, ease: "linear", repeat: Number.POSITIVE_INFINITY }}
			>
				{children}
				{children}
			</motion.div>
		</div>
	);
}

/** Blur settle reveal for inverse strips and panels. */
export function SeraBlurReveal({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const ref = useRef<HTMLDivElement>(null);
	const inView = useInView(ref, motionViewport);
	const reduceMotion = useReducedMotion();

	return (
		<motion.div
			animate={
				inView && !reduceMotion
					? { opacity: 1, y: 0, filter: "blur(0px)" }
					: undefined
			}
			className={className}
			initial={reduceMotion ? false : { opacity: 0, y: 8, filter: "blur(4px)" }}
			ref={ref}
			transition={spring}
		>
			{children}
		</motion.div>
	);
}

/** Hairline rule draws in from the left. */
export function SeraMaskRule({ className }: { className?: string }) {
	const ref = useRef<HTMLDivElement>(null);
	const inView = useInView(ref, motionViewport);
	const reduceMotion = useReducedMotion();

	return (
		<motion.div
			animate={inView ? { scaleX: 1 } : reduceMotion ? { scaleX: 1 } : { scaleX: 0 }}
			aria-hidden
			className={cn("h-px w-full origin-left bg-border", className)}
			initial={reduceMotion ? false : { scaleX: 0 }}
			ref={ref}
			transition={spring}
		/>
	);
}

/** Sharp-corner billing toggle for Sera pricing. */
export function SeraBillingToggle({
	period,
	onChange,
	layoutId = "sera-billing-pill",
}: {
	period: "monthly" | "annual";
	onChange: (period: "monthly" | "annual") => void;
	layoutId?: string;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<div
			aria-label="Billing period"
			className="inline-flex border border-border p-0.5"
			role="group"
		>
			{(["monthly", "annual"] as const).map((option) => {
				const isActive = period === option;
				return (
					<button
						aria-pressed={isActive}
						className={cn(
							"relative px-4 py-2 font-medium text-[11px] uppercase tracking-[0.2em] transition-colors active:scale-[0.96]",
							isActive ? "text-foreground" : "text-muted-foreground",
						)}
						key={option}
						onClick={() => onChange(option)}
						type="button"
					>
						{isActive ? (
							reduceMotion ? (
								<span className="absolute inset-0 -z-10 bg-muted" />
							) : (
								<motion.span
									className="absolute inset-0 -z-10 bg-muted"
									layoutId={layoutId}
									transition={spring}
								/>
							)
						) : null}
						{option === "monthly" ? "Monthly" : "Annual"}
					</button>
				);
			})}
		</div>
	);
}

/** Cross-fade price when billing period changes. */
export function SeraPriceReveal({
	amount,
	className,
}: {
	amount: string;
	className?: string;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<AnimatePresence initial={false} mode="popLayout">
			<motion.span
				animate={reduceMotion ? undefined : { opacity: 1, y: 0, filter: "blur(0px)" }}
				className={cn("font-medium tabular-nums tracking-tight", className)}
				exit={
					reduceMotion
						? undefined
						: {
								opacity: 0,
								y: -6,
								filter: "blur(4px)",
								transition: { duration: 0.15, ease: "easeIn" },
							}
				}
				initial={reduceMotion ? false : { opacity: 0, y: 8, filter: "blur(4px)" }}
				key={amount}
				transition={spring}
			>
				{amount}
			</motion.span>
		</AnimatePresence>
	);
}

/** Menu / close icon cross-fade for Sera header mobile toggle. */
export function SeraIconToggle({
	open,
	children,
}: {
	open: boolean;
	children: [ReactNode, ReactNode];
}) {
	const reduceMotion = useReducedMotion();
	const transition = reduceMotion ? { duration: 0 } : spring;

	return (
		<span className="relative inline-flex size-4 items-center justify-center">
			<motion.span
				animate={
					open
						? { opacity: 0, scale: 0.25, filter: "blur(4px)" }
						: { opacity: 1, scale: 1, filter: "blur(0px)" }
				}
				aria-hidden={open}
				className="absolute inset-0 inline-flex items-center justify-center"
				transition={transition}
			>
				{children[0]}
			</motion.span>
			<motion.span
				animate={
					open
						? { opacity: 1, scale: 1, filter: "blur(0px)" }
						: { opacity: 0, scale: 0.25, filter: "blur(4px)" }
				}
				aria-hidden={!open}
				className="absolute inset-0 inline-flex items-center justify-center"
				transition={transition}
			>
				{children[1]}
			</motion.span>
		</span>
	);
}

/** Stagger children when mobile drawer opens. */
export function SeraDrawerStagger({
	open,
	children,
	className,
}: {
	open: boolean;
	children: ReactNode;
	className?: string;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<motion.div
			animate={open ? "visible" : "hidden"}
			className={className}
			initial="hidden"
			variants={{
				hidden: {},
				visible: {
					transition: {
						staggerChildren: reduceMotion ? 0 : motionStagger.item,
						delayChildren: 0.06,
					},
				},
			}}
		>
			{children}
		</motion.div>
	);
}

export function SeraDrawerItem({
	children,
	className,
}: {
	children: ReactNode;
	className?: string;
}) {
	const reduceMotion = useReducedMotion();

	return (
		<motion.div
			className={className}
			variants={
				reduceMotion
					? { hidden: { opacity: 1, x: 0 }, visible: { opacity: 1, x: 0 } }
					: {
							hidden: { opacity: 0, x: -8, filter: "blur(4px)" },
							visible: {
								opacity: 1,
								x: 0,
								filter: "blur(0px)",
								transition: spring,
							},
						}
			}
		>
			{children}
		</motion.div>
	);
}
```

### `registry/blocks/pricing/11/pricing-section.tsx`

```tsx
"use client";

import { useState } from "react";
import { ArrowRightIcon, CheckIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { SectionShell, ContentRail } from "@/components/layout-contract";
import {
	SeraBillingToggle,
	SeraPriceReveal,
	SeraStagger,
	SeraStaggerItem,
} from "../../sera/sera-motion";

type BillingPeriod = "monthly" | "annual";

const plans = [
	{
		name: "Starter",
		monthly: "$0",
		annual: "$0",
		description: "For solo operators mapping their first Sera workspace.",
		features: [
			"1 workspace",
			"Up to 3 members",
			"Core ledger views",
			"7-day activity history",
			"Community support",
		],
		cta: "Start free",
		highlighted: false,
	},
	{
		name: "Growth",
		monthly: "$24",
		annual: "$19",
		description: "For teams running Sera as their daily operating surface.",
		features: [
			"Unlimited workspaces",
			"Up to 25 members",
			"Automation rules",
			"90-day activity history",
			"Priority support",
		],
		cta: "Deploy Growth",
		highlighted: true,
	},
	{
		name: "Scale",
		monthly: "$96",
		annual: "$76",
		description: "For organizations standardizing every team on Sera.",
		features: [
			"Unlimited members",
			"SSO and SCIM provisioning",
			"Audit log export",
			"Unlimited history",
			"Dedicated success manager",
		],
		cta: "Contact sales",
		highlighted: false,
	},
];

export function PricingSeraSection() {
	const [period, setPeriod] = useState<BillingPeriod>("monthly");

	return (
		<SectionShell spacingMode="section">
			<ContentRail maxWidth="max-w-5xl" className="space-y-12">
				<SeraStagger className="space-y-12">
					<SeraStaggerItem>
						<div className="flex flex-col gap-6 sm:flex-row sm:items-end sm:justify-between">
							<div className="max-w-xl">
								<p className="text-[11px] uppercase tracking-[0.2em] text-muted-foreground">
									Pricing
								</p>
								<h2 className="mt-3 text-balance font-medium text-3xl tracking-tight md:text-4xl">
									One ledger, three tiers
								</h2>
								<p className="mt-4 text-pretty text-muted-foreground text-sm leading-relaxed md:text-base">
									Every plan runs the same monochrome workspace. Pay only for the scale
									you operate at.
								</p>
							</div>
							<SeraBillingToggle
								layoutId="pricing-11-sera-pill"
								onChange={setPeriod}
								period={period}
							/>
						</div>
					</SeraStaggerItem>

					<SeraStaggerItem>
						<SeraStagger className="grid grid-cols-1 border-t border-l border-border md:grid-cols-3">
							{plans.map((plan) => {
								const price = period === "monthly" ? plan.monthly : plan.annual;

								return (
									<SeraStaggerItem key={plan.name}>
										<div
											className={cn(
												"flex h-full flex-col gap-6 border-b border-r border-border p-6",
												plan.highlighted && "bg-primary text-primary-foreground",
											)}
										>
											<div className="flex items-center justify-between gap-2">
												<p
													className={cn(
														"text-[11px] uppercase tracking-[0.2em]",
														plan.highlighted
															? "text-primary-foreground/70"
															: "text-muted-foreground",
													)}
												>
													{plan.name}
												</p>
												{plan.highlighted ? (
													<span className="border border-primary-foreground/30 px-2 py-0.5 text-[10px] uppercase tracking-[0.2em]">
														Most deployed
													</span>
												) : null}
											</div>

											<div className="flex items-baseline gap-1.5">
												<SeraPriceReveal
													amount={price}
													className="text-4xl tracking-tight"
												/>
												<span
													className={cn(
														"font-mono text-xs",
														plan.highlighted
															? "text-primary-foreground/70"
															: "text-muted-foreground",
													)}
												>
													/mo
												</span>
											</div>

											<p
												className={cn(
													"text-sm leading-relaxed",
													plan.highlighted
														? "text-primary-foreground/70"
														: "text-muted-foreground",
												)}
											>
												{plan.description}
											</p>

											<ul>
												{plan.features.map((feature) => (
													<li
														className={cn(
															"flex items-center gap-2 border-t py-2.5 text-sm",
															plan.highlighted
																? "border-primary-foreground/30"
																: "border-border",
														)}
														key={feature}
													>
														<CheckIcon
															className={cn(
																"size-3.5 shrink-0",
																plan.highlighted
																	? "text-primary-foreground/70"
																	: "text-muted-foreground",
															)}
														/>
														<span className="min-w-0">{feature}</span>
													</li>
												))}
											</ul>

											<Button
												className="mt-auto w-full"
												variant={plan.highlighted ? "secondary" : "outline"}
											>
												{plan.cta}
												<ArrowRightIcon data-icon="inline-end" />
											</Button>
										</div>
									</SeraStaggerItem>
								);
							})}
						</SeraStagger>
					</SeraStaggerItem>
				</SeraStagger>
			</ContentRail>
		</SectionShell>
	);
}
```
