Setup Guide
One-time setup for using BOOTH // NEXT components. Add these to your project, then copy any component from the theme.
The cn() utility combines clsx and tailwind-merge for conditional class names. Install both packages.
npm install clsx tailwind-mergeCreate lib/utils.ts with the cn() helper. Every component imports this for class name merging.
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs))
}Add the BOOTH // NEXT design tokens to your globals.css. These define colors, fonts, and animation tokens used by every component in the theme.
@theme {
/* ── Colors ─────────────────────────────────────────── */
--color-booth-ivory: #F7F0E0;
--color-booth-ivory-alt: #EEE5CE;
--color-booth-ivory-deep: #E4D8BB;
--color-booth-red: #C8203A;
--color-booth-red-dark: #A01830;
--color-booth-red-light: #E8364F;
--color-booth-teal: #1E8A82;
--color-booth-teal-dark: #156860;
--color-booth-teal-light: #2AADA3;
--color-booth-ink: #1C1207;
--color-booth-ink-mid: #3D2E18;
--color-booth-ink-muted: #7A6A50;
--color-booth-chrome: #C4B89A;
--color-booth-chrome-light: #DDD3BC;
--color-booth-white: #FDFAF3;
--color-booth-text: #1C1207;
--color-booth-text-muted: #7A6A50;
/* ── Fonts ──────────────────────────────────────────── */
--font-display: 'Righteous', sans-serif;
--font-body: var(--font-dm-sans);
--font-mono: var(--font-dm-mono);
/* ── Animations ─────────────────────────────────────── */
--animate-float: booth-float 4s ease-in-out infinite;
--animate-pulse-dot: booth-pulse-dot 2.5s ease-in-out infinite;
}Each component may need its own CSS classes in your globals.css. Copy the styles for the components you use.
/* ─── Buttons ────────────────────────────────────────── */
.btn-base {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
font-family: var(--font-body);
font-weight: 600;
border: 2px solid transparent;
border-radius: 999px;
cursor: pointer;
text-decoration: none;
line-height: 1;
transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.1s;
white-space: nowrap;
}
.btn-base:hover { transform: translateY(-1px); text-decoration: none; }
.btn-base:active { transform: translateY(1px); }
.btn-sm { font-size: 13px; padding: 7px 16px; }
.btn-md { font-size: 15px; padding: 11px 22px; }
.btn-lg { font-size: 15px; padding: 14px 32px; }
.btn-primary {
background: var(--color-booth-red);
color: var(--color-booth-white);
border-color: var(--color-booth-red);
}
.btn-primary:hover {
background: var(--color-booth-red-light);
border-color: var(--color-booth-red-light);
color: var(--color-booth-white);
}
.btn-secondary {
background: rgba(30, 138, 130, 0.15);
color: var(--color-booth-teal-light);
border-color: rgba(30, 138, 130, 0.35);
}
.btn-secondary:hover {
background: rgba(30, 138, 130, 0.25);
border-color: rgba(30, 138, 130, 0.5);
color: var(--color-booth-teal-light);
}
.btn-ghost {
background: transparent;
color: var(--color-booth-chrome-light);
border-color: rgba(196, 184, 154, 0.35);
}
.btn-ghost:hover {
border-color: var(--color-booth-chrome-light);
color: var(--color-booth-white);
}
.btn-primary--light {
background: var(--color-booth-red);
color: var(--color-booth-white);
border-color: var(--color-booth-red);
}
.btn-primary--light:hover {
background: var(--color-booth-red-light);
border-color: var(--color-booth-red-light);
}
.btn-secondary--light {
background: transparent;
color: var(--color-booth-teal-dark);
border-color: var(--color-booth-teal);
}
.btn-secondary--light:hover {
background: rgba(30, 138, 130, 0.08);
color: var(--color-booth-teal-dark);
}
.btn-ghost--light {
background: transparent;
color: var(--color-booth-ink-mid);
border-color: var(--color-booth-ivory-deep);
}
.btn-ghost--light:hover {
border-color: var(--color-booth-ink-muted);
color: var(--color-booth-ink);
}/* ─── Badges ─────────────────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
gap: 4px;
font-family: var(--font-mono);
font-weight: 500;
font-size: 10px;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 3px 9px;
border-radius: 999px;
border: 1px solid transparent;
}
.badge--red {
background: rgba(200, 32, 58, 0.08);
color: var(--color-booth-red);
border-color: rgba(200, 32, 58, 0.2);
}
.badge--teal {
background: rgba(30, 138, 130, 0.08);
color: var(--color-booth-teal);
border-color: rgba(30, 138, 130, 0.2);
}
.badge--chrome {
background: rgba(196, 184, 154, 0.12);
color: var(--color-booth-ink-muted);
border-color: rgba(196, 184, 154, 0.25);
}
.badge--ink {
background: rgba(28, 18, 7, 0.06);
color: var(--color-booth-ink-mid);
border-color: rgba(28, 18, 7, 0.12);
}/* ─── Text Variants ──────────────────────────────────── */
.text-body { font-size: 14px; line-height: 1.6; font-weight: 400; color: var(--color-booth-ink-muted); }
.text-caption { font-size: 12px; font-weight: 500; color: var(--color-booth-ink-muted); }
.text-label {
font-family: var(--font-mono);
font-size: 10px;
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
color: rgba(196, 184, 154, 0.5);
}
.text-code { font-family: var(--font-mono); font-size: 13px; color: var(--color-booth-teal-dark); }/* ─── Features Section ───────────────────────────────── */
.booth-card {
background: var(--color-booth-white);
padding: 36px 32px;
display: flex;
flex-direction: column;
gap: 12px;
transition: background 0.15s;
position: relative;
}
.booth-card:hover { background: #FEFCF6; }
.booth-card::before {
content: '';
position: absolute;
top: 0; left: 0;
width: 100%; height: 3px;
background: transparent;
transition: background 0.15s;
}
.booth-card:hover::before { background: var(--color-booth-red); }
.card-icon-el {
width: 44px;
height: 44px;
border-radius: 12px;
background: var(--color-booth-ivory-alt);
border: 1px solid var(--color-booth-ivory-deep);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.card-title {
font-family: var(--font-display);
font-size: 18px;
color: var(--color-booth-ink);
line-height: 1.2;
}
.card-description {
font-size: 14px;
color: var(--color-booth-ink-muted);
line-height: 1.6;
}Button
Retro diner button with primary, secondary, and ghost variants in three sizes. Cherry red accent, bold uppercase labels. Renders as a Next.js Link when an href is provided.
Badge
Diner-styled badge with four color variants: red, teal, chrome, and ink. Suited for category labels, tags, and status indicators.
Text
Polymorphic text primitive with body, caption, label, and code variants. Renders as p, span, or div via the `as` prop.
Card
Composable card with Card, CardHeader, CardBody, and CardFooter sub-components. Warm ivory surfaces with diner-styled borders.