The Kit/Components/Button
Button
Primary, secondary and ghost actions in three committed languages: instrument pill, broadsheet plate, painted poster block. Self-contained, theme-aware, copy one file.
Apex
"use client";
import * as React from "react";
/* Apex Button - racing-instrument pill: mono caps, accent fill with a soft signal
bloom (this family's shipped look), outline + ghost steps. Colour from theme vars. */
const INK_ON_ACCENT = "#06070d";
type Variant = "primary" | "secondary" | "ghost";
const base: React.CSSProperties = {
display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7,
fontFamily: "var(--font-mono)", fontWeight: 600, fontSize: 11.5, lineHeight: 1,
textTransform: "uppercase", letterSpacing: "0.12em", whiteSpace: "nowrap",
padding: "8px 16px", borderRadius: 999, border: "1px solid transparent",
cursor: "pointer", transition: "background .16s ease, border-color .16s ease, color .16s ease, box-shadow .16s ease, filter .16s ease",
};
export function Button({
variant = "primary", children, style, ...rest
}: React.ButtonHTMLAttributes<HTMLButtonElement> & { variant?: Variant }) {
const [h, setH] = React.useState(false);
const v: Record<Variant, React.CSSProperties> = {
primary: {
background: "var(--accent)", color: INK_ON_ACCENT,
boxShadow: `0 0 18px -2px color-mix(in srgb, var(--accent) ${h ? 72 : 55}%, transparent)`,
filter: h ? "brightness(1.06)" : "none",
},
secondary: {
background: h ? "color-mix(in srgb, var(--accent) 14%, transparent)" : "transparent",
color: "var(--accent)", border: "1px solid color-mix(in srgb, var(--accent) 42%, var(--line))",
},
ghost: {
background: h ? "color-mix(in srgb, var(--accent) 10%, transparent)" : "transparent",
color: h ? "var(--ink)" : "var(--ink-dim)",
},
};
return (
<button {...rest} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
style={{ ...base, ...v[variant], ...style }}>
{children}
</button>
);
}
Tifo
"use client";
import React, { useState } from "react";
/* Tifo Button - broadsheet matchday: sharp 3px corners, condensed display caps
with wide tracking, flat accent strike-fill. No glow anywhere. */
const T = "color 120ms ease, background-color 120ms ease, border-color 120ms ease";
const ACCENT_INK = "#08080a";
export function Button(
props: React.ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary" | "ghost";
}
) {
const { variant = "secondary", style, onMouseEnter, onMouseLeave, ...rest } = props;
const [hover, setHover] = useState(false);
const base: React.CSSProperties = {
display: "inline-flex", alignItems: "center", gap: 8, borderRadius: 3,
fontFamily: "var(--font-display)", textTransform: "uppercase",
letterSpacing: "0.14em", fontWeight: 700, fontSize: 13, lineHeight: 1,
padding: "9px 16px", cursor: "pointer", transition: T,
};
let v: React.CSSProperties;
let hv: React.CSSProperties = {};
if (variant === "primary") {
v = { background: "var(--accent)", border: "1px solid var(--accent)", color: ACCENT_INK };
hv = hover ? { background: "var(--accent-2)", borderColor: "var(--accent-2)" } : {};
} else if (variant === "ghost") {
v = { background: "transparent", border: "1px solid var(--line)", color: "var(--ink-dim)" };
hv = hover ? { color: "var(--ink)" } : {};
} else {
v = { background: "var(--surface-2)", border: "1px solid var(--line)", color: "var(--ink-dim)" };
hv = hover ? { borderColor: "var(--accent)", color: "var(--ink)" } : {};
}
return (
<button
{...rest}
onMouseEnter={(e) => { setHover(true); onMouseEnter?.(e); }}
onMouseLeave={(e) => { setHover(false); onMouseLeave?.(e); }}
style={{ ...base, ...v, ...hv, ...style }}
/>
);
}
Ink
"use client";
import React, { useState } from "react";
/* Ink Button - painted poster plate: condensed display caps, solid accent fill,
double-plate cel shadow (the accent's own darker step, then near-black). Zero
blur, zero glow - depth is stacked solid colour. Born in the library. */
const T = "background-color 140ms ease, transform 140ms cubic-bezier(0.22,1,0.36,1), box-shadow 140ms cubic-bezier(0.22,1,0.36,1)";
const PUNCH = "color-mix(in srgb, var(--bg) 40%, #000)";
export function Button(
props: React.ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary" | "ghost";
}
) {
const { variant = "primary", style, onMouseEnter, onMouseLeave, ...rest } = props;
const [hover, setHover] = useState(false);
const shade = "color-mix(in srgb, var(--accent) 62%, #000)";
const base: React.CSSProperties = {
display: "inline-flex", alignItems: "center", gap: 8, borderRadius: 2,
fontFamily: "var(--font-display)", textTransform: "uppercase",
letterSpacing: "0.06em", fontWeight: 700, fontSize: 13.5, lineHeight: 1,
padding: "10px 18px", border: "none", cursor: "pointer", transition: T,
transform: hover ? "translate(-2px, -2px)" : "none",
};
let v: React.CSSProperties;
if (variant === "primary") {
v = {
background: hover ? "color-mix(in srgb, var(--accent) 88%, #fff)" : "var(--accent)",
color: PUNCH,
boxShadow: hover ? `5px 5px 0 ${shade}, 9px 9px 0 ${PUNCH}` : `3px 3px 0 ${shade}, 6px 6px 0 ${PUNCH}`,
};
} else if (variant === "ghost") {
v = {
background: "transparent", color: "var(--ink-dim)",
boxShadow: hover ? `0 3px 0 var(--accent)` : "0 3px 0 var(--line)",
borderRadius: 0, paddingInline: 6,
};
} else {
v = {
background: "var(--surface-2)", color: "var(--ink)",
boxShadow: hover ? `5px 5px 0 ${PUNCH}` : `3px 3px 0 ${PUNCH}`,
};
}
return (
<button
{...rest}
onMouseEnter={(e) => { setHover(true); onMouseEnter?.(e); }}
onMouseLeave={(e) => { setHover(false); onMouseLeave?.(e); }}
style={{ ...base, ...v, ...style }}
/>
);
}