Setup Guide
One-time setup for using LAB // 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 LAB // NEXT design tokens to your globals.css. These define colors, fonts, and animation tokens used by every component in the theme.
@theme {
/* ── Colors ─────────────────────────────────────────── */
--color-lab-bg: #040810;
--color-lab-bg-2: #060d1a;
--color-lab-bg-3: #091525;
--color-lab-blue: #00d4ff;
--color-lab-green: #00ff9d;
--color-lab-text: #d8eef5;
/* ── Fonts ───────────────────────────────────────────── */
--font-display: var(--font-oxanium);
--font-body: var(--font-jetbrains-mono);
/* ── Animations ──────────────────────────────────────── */
--animate-blink-pulse: blink-pulse 2.4s ease-in-out infinite;
--animate-nuc-pulse: nuc-pulse 2.8s ease-in-out infinite;
--animate-scan: scanline 8s linear 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: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
cursor: pointer;
text-decoration: none;
line-height: 1;
white-space: nowrap;
transition: all 0.2s;
border: none;
outline: none;
}
.btn-sm { font-size: 0.68rem; padding: 9px 22px; }
.btn-md { font-size: 0.76rem; padding: 12px 28px; }
.btn-lg { font-size: 0.82rem; padding: 15px 36px; }
.btn-primary {
color: var(--color-lab-bg);
background: linear-gradient(135deg, #00d4ff 0%, #0099bb 100%);
clip-path: polygon(10px 0%, 100% 0%, calc(100% - 10px) 100%, 0% 100%);
}
.btn-primary:hover {
background: linear-gradient(135deg, #00ff9d 0%, #00bb74 100%);
transform: translateY(-1px);
}
.btn-primary:active { transform: translateY(0); }
.btn-secondary {
color: var(--color-lab-blue);
background: transparent;
border: 1px solid var(--blue-border);
clip-path: polygon(10px 0%, 100% 0%, calc(100% - 10px) 100%, 0% 100%);
}
.btn-secondary:hover {
border-color: var(--color-lab-blue);
background: var(--blue-dim);
}
.btn-ghost {
color: var(--text-muted);
background: transparent;
border: 1px solid rgba(216, 238, 245, 0.12);
}
.btn-ghost:hover { color: var(--color-lab-text); border-color: rgba(216, 238, 245, 0.3); }/* ─── Badges ─────────────────────────────────────────── */
.badge {
display: inline-flex;
align-items: center;
font-weight: 700;
font-size: 0.6rem;
letter-spacing: 0.16em;
text-transform: uppercase;
padding: 2px 9px;
}
.badge--blue { color: var(--color-lab-blue); border: 1px solid var(--blue-border); background: var(--blue-dim); }
.badge--green { color: var(--color-lab-green); border: 1px solid var(--green-border); background: var(--green-dim); }/* ─── Features Section ───────────────────────────────── */
.lab-feat-card {
background: var(--color-lab-bg);
padding: 36px 30px;
position: relative;
overflow: hidden;
transition: background 0.25s;
}
.lab-feat-card::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 2px;
background: linear-gradient(90deg, transparent, var(--color-lab-blue), transparent);
opacity: 0;
transition: opacity 0.3s;
}
.lab-feat-card:hover { background: rgba(0, 212, 255, 0.04); }
.lab-feat-card:hover::after { opacity: 1; }
.feat-exp {
font-size: 0.6rem;
font-weight: 700;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--text-faint);
margin-bottom: 22px;
}
.feat-icon-el {
width: 40px;
height: 40px;
margin-bottom: 18px;
color: var(--color-lab-blue);
}
.feat-title {
font-family: var(--font-display);
font-size: 1rem;
font-weight: 600;
letter-spacing: 0.02em;
margin-bottom: 10px;
color: var(--color-lab-text);
}
.feat-desc {
font-size: 0.78rem;
color: var(--text-muted);
line-height: 1.75;
}/* ─── Text Variants ──────────────────────────────────── */
.text-body { font-size: 0.875rem; line-height: 1.8; color: var(--text-muted); }
.text-caption { font-size: 0.78rem; color: var(--text-faint); }
.text-label { font-size: 0.62rem; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint); }
.text-code { font-family: var(--font-body), monospace; font-size: 0.82rem; color: var(--color-lab-blue); }Button
Scientific dark-theme button with primary, secondary, and ghost variants in three sizes. Renders as a Next.js Link when an href is provided.
Badge
Lab-aesthetic badge with green and blue pill variants for experiment tags and status markers.
Card
Feature card with an experiment code label, SVG icon (atom, grid, diamond, network, monitor, warning), description, and a colored pill tag.
Text
Polymorphic text primitive with body, caption, label, and code variants styled for the LAB dark scientific palette.