"use client";
import * as React from "react";
import { motion, useReducedMotion, type Variants } from "motion/react";
import { cn } from "@/lib/utils";
export interface ClickPowerUpProps extends Omit<
React.ButtonHTMLAttributes<HTMLButtonElement>,
"onDrag" | "onDragStart" | "onDragEnd" | "onAnimationStart"
> {
/** Milliseconds the powered-up flash lasts after a click. */
tapDuration?: number;
/** Color of the powered-up flash. */
accentColor?: string;
}
type Phase = "rest" | "hover" | "tap" | "powered";
const SPRING = { type: "spring", stiffness: 320, damping: 22 } as const;
const CORNERS = [
{ key: "tl", x: -1, y: -1, className: "top-0 left-0 border-t border-l" },
{ key: "tr", x: 1, y: -1, className: "top-0 right-0 border-t border-r" },
{ key: "bl", x: -1, y: 1, className: "bottom-0 left-0 border-b border-l" },
{ key: "br", x: 1, y: 1, className: "right-0 bottom-0 border-r border-b" },
] as const;
const bracketVariants: Variants = {
rest: { x: 0, y: 0, opacity: 0.45 },
hover: ({ x, y }: { x: number; y: number }) => ({
x: x * 4,
y: y * 4,
opacity: 1,
}),
tap: ({ x, y }: { x: number; y: number }) => ({
x: -x * 2,
y: -y * 2,
opacity: 1,
}),
// Bouncy spring so the brackets overshoot outward, then settle.
powered: ({ x, y }: { x: number; y: number }) => ({
x: x * 6,
y: y * 6,
opacity: 1,
transition: { type: "spring", stiffness: 600, damping: 11 },
}),
};
const panelVariants: Variants = {
rest: { scaleX: 0 },
hover: { scaleX: 1 },
tap: { scaleX: 1 },
powered: { scaleX: 1 },
};
export const ClickPowerUp = React.forwardRef<
HTMLButtonElement,
ClickPowerUpProps
>(
(
{
children,
className,
tapDuration = 500,
accentColor = "#2CD4BD",
onClick,
onPointerEnter,
onPointerLeave,
onPointerDown,
onPointerUp,
style,
disabled,
type = "button",
...props
},
ref,
) => {
const reduceMotion = useReducedMotion();
const [hovered, setHovered] = React.useState(false);
const [pressed, setPressed] = React.useState(false);
const [powered, setPowered] = React.useState(false);
const poweredTimerRef = React.useRef<number | undefined>(undefined);
React.useEffect(
() => () => window.clearTimeout(poweredTimerRef.current),
[],
);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
onClick?.(event);
setPowered(true);
window.clearTimeout(poweredTimerRef.current);
poweredTimerRef.current = window.setTimeout(
() => setPowered(false),
tapDuration,
);
};
// Pressing wins so every click, even mid power-up, snaps in then bursts out.
const phase: Phase = pressed
? "tap"
: powered
? "powered"
: hovered
? "hover"
: "rest";
return (
<motion.button
ref={ref}
type={type}
disabled={disabled}
initial={false}
animate={phase}
onClick={handleClick}
onPointerDown={(event) => {
onPointerDown?.(event);
if (event.button === 0) setPressed(true);
}}
onPointerUp={(event) => {
onPointerUp?.(event);
setPressed(false);
}}
onPointerCancel={() => setPressed(false)}
onPointerEnter={(event) => {
onPointerEnter?.(event);
if (event.pointerType !== "touch") setHovered(true);
}}
onPointerLeave={(event) => {
onPointerLeave?.(event);
setHovered(false);
setPressed(false);
}}
style={{ "--powerup": accentColor, ...style } as React.CSSProperties}
className={cn(
"group/powerup relative inline-flex cursor-pointer items-center justify-center px-10 py-3 text-sm font-medium tracking-[0.18em] uppercase shadow-[0_1px_2px_rgb(0_0_0/0.05),0_2px_6px_-3px_rgb(0_0_0/0.07),inset_0_-1px_0_rgb(0_0_0/0.03)] dark:shadow-[0_1px_2px_rgb(0_0_0/0.4),inset_0_1px_0_rgb(255_255_255/0.05)] outline-none select-none",
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
>
{/* Face: hatched surface with a panel that wipes in when armed. */}
<span
aria-hidden
className="absolute inset-0 overflow-hidden bg-background [--hatch:color-mix(in_oklab,var(--foreground)_10%,transparent)]"
>
<span className="absolute inset-0 bg-[repeating-linear-gradient(315deg,var(--hatch)_0,var(--hatch)_1px,transparent_0,transparent_50%)] bg-size-[7px_7px]" />
<motion.span
variants={panelVariants}
transition={SPRING}
className="absolute inset-0 origin-left bg-foreground"
/>
<motion.span
className="absolute inset-0 bg-(--powerup)"
initial={false}
animate={{ opacity: powered ? 1 : 0 }}
transition={{ duration: powered ? 0.08 : 0.3 }}
/>
</span>
{CORNERS.map((corner) => (
<motion.span
key={corner.key}
aria-hidden
custom={corner}
variants={reduceMotion ? undefined : bracketVariants}
transition={SPRING}
className={cn(
"pointer-events-none absolute z-10 size-2.5 border-foreground",
phase === "powered" && "border-(--powerup)",
corner.className,
)}
/>
))}
<motion.span
className={cn(
"relative z-10 transition-colors duration-150",
phase === "rest" && "text-foreground",
(phase === "hover" || phase === "tap") && "text-background",
phase === "powered" && "text-neutral-950",
)}
variants={{
rest: { scale: 1 },
hover: { scale: 1 },
tap: { scale: 0.94 },
powered: reduceMotion
? { scale: 1 }
: {
scale: 1,
transition: { type: "spring", stiffness: 600, damping: 12 },
},
}}
transition={SPRING}
>
{children}
</motion.span>
</motion.button>
);
},
);
ClickPowerUp.displayName = "ClickPowerUp";
Button Demo
By jay sharma
Try the interaction, copy the React source files, or download the complete example.
About Button Demo
Button Demo is an animated React and Tailwind CSS button by jay sharma. Try the interaction, copy the React source, or download the example with creator credit.
- Effects and categories
- Hover effects, Animated
- Using this example
- Copy a TSX file or download the original source and standalone demo. Test keyboard focus, motion and contrast in your own project.
Usage, Tailwind and licensing questions
Read the source files
import-examples/click-power-up.tsx
import { ClickPowerUp } from "@/components/evil-buttons/click-powerup";
export function ButtonDemo() {
return (
<ClickPowerUp onClick={() => console.log("Powered up")}>
Launch
</ClickPowerUp>
);
}
components/evil-buttons/click-powerup.tsx
"use client";
import * as React from "react";
import { motion, useReducedMotion, type Variants } from "motion/react";
import { cn } from "@/lib/utils";
export interface ClickPowerUpProps extends Omit<
React.ButtonHTMLAttributes<HTMLButtonElement>,
"onDrag" | "onDragStart" | "onDragEnd" | "onAnimationStart"
> {
/** Milliseconds the powered-up flash lasts after a click. */
tapDuration?: number;
/** Color of the powered-up flash. */
accentColor?: string;
}
type Phase = "rest" | "hover" | "tap" | "powered";
const SPRING = { type: "spring", stiffness: 320, damping: 22 } as const;
const CORNERS = [
{ key: "tl", x: -1, y: -1, className: "top-0 left-0 border-t border-l" },
{ key: "tr", x: 1, y: -1, className: "top-0 right-0 border-t border-r" },
{ key: "bl", x: -1, y: 1, className: "bottom-0 left-0 border-b border-l" },
{ key: "br", x: 1, y: 1, className: "right-0 bottom-0 border-r border-b" },
] as const;
const bracketVariants: Variants = {
rest: { x: 0, y: 0, opacity: 0.45 },
hover: ({ x, y }: { x: number; y: number }) => ({
x: x * 4,
y: y * 4,
opacity: 1,
}),
tap: ({ x, y }: { x: number; y: number }) => ({
x: -x * 2,
y: -y * 2,
opacity: 1,
}),
// Bouncy spring so the brackets overshoot outward, then settle.
powered: ({ x, y }: { x: number; y: number }) => ({
x: x * 6,
y: y * 6,
opacity: 1,
transition: { type: "spring", stiffness: 600, damping: 11 },
}),
};
const panelVariants: Variants = {
rest: { scaleX: 0 },
hover: { scaleX: 1 },
tap: { scaleX: 1 },
powered: { scaleX: 1 },
};
export const ClickPowerUp = React.forwardRef<
HTMLButtonElement,
ClickPowerUpProps
>(
(
{
children,
className,
tapDuration = 500,
accentColor = "#2CD4BD",
onClick,
onPointerEnter,
onPointerLeave,
onPointerDown,
onPointerUp,
style,
disabled,
type = "button",
...props
},
ref,
) => {
const reduceMotion = useReducedMotion();
const [hovered, setHovered] = React.useState(false);
const [pressed, setPressed] = React.useState(false);
const [powered, setPowered] = React.useState(false);
const poweredTimerRef = React.useRef<number | undefined>(undefined);
React.useEffect(
() => () => window.clearTimeout(poweredTimerRef.current),
[],
);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
onClick?.(event);
setPowered(true);
window.clearTimeout(poweredTimerRef.current);
poweredTimerRef.current = window.setTimeout(
() => setPowered(false),
tapDuration,
);
};
// Pressing wins so every click, even mid power-up, snaps in then bursts out.
const phase: Phase = pressed
? "tap"
: powered
? "powered"
: hovered
? "hover"
: "rest";
return (
<motion.button
ref={ref}
type={type}
disabled={disabled}
initial={false}
animate={phase}
onClick={handleClick}
onPointerDown={(event) => {
onPointerDown?.(event);
if (event.button === 0) setPressed(true);
}}
onPointerUp={(event) => {
onPointerUp?.(event);
setPressed(false);
}}
onPointerCancel={() => setPressed(false)}
onPointerEnter={(event) => {
onPointerEnter?.(event);
if (event.pointerType !== "touch") setHovered(true);
}}
onPointerLeave={(event) => {
onPointerLeave?.(event);
setHovered(false);
setPressed(false);
}}
style={{ "--powerup": accentColor, ...style } as React.CSSProperties}
className={cn(
"group/powerup relative inline-flex cursor-pointer items-center justify-center px-10 py-3 text-sm font-medium tracking-[0.18em] uppercase shadow-[0_1px_2px_rgb(0_0_0/0.05),0_2px_6px_-3px_rgb(0_0_0/0.07),inset_0_-1px_0_rgb(0_0_0/0.03)] dark:shadow-[0_1px_2px_rgb(0_0_0/0.4),inset_0_1px_0_rgb(255_255_255/0.05)] outline-none select-none",
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
>
{/* Face: hatched surface with a panel that wipes in when armed. */}
<span
aria-hidden
className="absolute inset-0 overflow-hidden bg-background [--hatch:color-mix(in_oklab,var(--foreground)_10%,transparent)]"
>
<span className="absolute inset-0 bg-[repeating-linear-gradient(315deg,var(--hatch)_0,var(--hatch)_1px,transparent_0,transparent_50%)] bg-size-[7px_7px]" />
<motion.span
variants={panelVariants}
transition={SPRING}
className="absolute inset-0 origin-left bg-foreground"
/>
<motion.span
className="absolute inset-0 bg-(--powerup)"
initial={false}
animate={{ opacity: powered ? 1 : 0 }}
transition={{ duration: powered ? 0.08 : 0.3 }}
/>
</span>
{CORNERS.map((corner) => (
<motion.span
key={corner.key}
aria-hidden
custom={corner}
variants={reduceMotion ? undefined : bracketVariants}
transition={SPRING}
className={cn(
"pointer-events-none absolute z-10 size-2.5 border-foreground",
phase === "powered" && "border-(--powerup)",
corner.className,
)}
/>
))}
<motion.span
className={cn(
"relative z-10 transition-colors duration-150",
phase === "rest" && "text-foreground",
(phase === "hover" || phase === "tap") && "text-background",
phase === "powered" && "text-neutral-950",
)}
variants={{
rest: { scale: 1 },
hover: { scale: 1 },
tap: { scale: 0.94 },
powered: reduceMotion
? { scale: 1 }
: {
scale: 1,
transition: { type: "spring", stiffness: 600, damping: 12 },
},
}}
transition={SPRING}
>
{children}
</motion.span>
</motion.button>
);
},
);
ClickPowerUp.displayName = "ClickPowerUp";
lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
demo.tsx
export { ButtonDemo as default } from "@/import-examples/click-power-up";CSS
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
:root, :host {
--color-neutral-950: oklch(14.5% 0 none);
--spacing: 0.25rem;
--text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875);
--font-weight-medium: 500;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif;
--default-mono-font-family: var(--font-geist-mono);
}
}
@layer base {
*, ::after, ::before, ::backdrop, ::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html, :host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1, h2, h3, h4, h5, h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b, strong {
font-weight: bolder;
}
code, kbd, samp, pre {
font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
:-moz-focusring:where(:not(iframe)) {
outline: auto;
}
progress {
vertical-align: baseline;
}
summary {
display: list-item;
}
ol, ul, menu {
list-style: none;
}
img, svg, video, canvas, audio, iframe, embed, object {
display: block;
vertical-align: middle;
}
img, video {
max-width: 100%;
height: auto;
}
button, input, select, optgroup, textarea, ::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
border-radius: 0;
background-color: transparent;
opacity: 1;
}
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
::file-selector-button {
margin-inline-end: 4px;
}
::placeholder {
opacity: 1;
}
@supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
::placeholder {
color: currentcolor;
@supports (color: color-mix(in lab, red, red)) {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
}
textarea {
resize: vertical;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-date-and-time-value {
min-height: 1lh;
text-align: inherit;
}
::-webkit-datetime-edit {
display: inline-flex;
}
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
::-webkit-calendar-picker-indicator {
line-height: 1;
}
:-moz-ui-invalid {
box-shadow: none;
}
button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
appearance: button;
}
::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
height: auto;
}
[hidden]:where(:not([hidden="until-found"])) {
display: none !important;
}
}
@layer utilities {
.pointer-events-none {
pointer-events: none;
}
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.inset-0 {
inset: 0px;
}
.top-0 {
top: 0px;
}
.right-0 {
right: 0px;
}
.bottom-0 {
bottom: 0px;
}
.left-0 {
left: 0px;
}
.z-10 {
z-index: 10;
}
.inline-flex {
display: inline-flex;
}
.size-2\.5 {
width: calc(var(--spacing) * 2.5);
height: calc(var(--spacing) * 2.5);
}
.origin-left {
transform-origin: 0;
}
.cursor-pointer {
cursor: pointer;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.overflow-hidden {
overflow: hidden;
}
.border-t {
border-top-style: var(--tw-border-style);
border-top-width: 1px;
}
.border-r {
border-right-style: var(--tw-border-style);
border-right-width: 1px;
}
.border-b {
border-bottom-style: var(--tw-border-style);
border-bottom-width: 1px;
}
.border-l {
border-left-style: var(--tw-border-style);
border-left-width: 1px;
}
.border-\(--powerup\) {
border-color: var(--powerup);
}
.border-foreground {
border-color: var(--foreground);
}
.bg-\(--powerup\) {
background-color: var(--powerup);
}
.bg-background {
background-color: var(--background);
}
.bg-foreground {
background-color: var(--foreground);
}
.bg-\[repeating-linear-gradient\(315deg\,var\(--hatch\)_0\,var\(--hatch\)_1px\,transparent_0\,transparent_50\%\)\] {
background-image: repeating-linear-gradient(315deg,var(--hatch) 0,var(--hatch) 1px,transparent 0,transparent 50%);
}
.bg-size-\[7px_7px\] {
background-size: 7px 7px;
}
.px-10 {
padding-inline: calc(var(--spacing) * 10);
}
.py-3 {
padding-block: calc(var(--spacing) * 3);
}
.text-sm {
font-size: var(--text-sm);
line-height: var(--tw-leading, var(--text-sm--line-height));
}
.font-medium {
--tw-font-weight: var(--font-weight-medium);
font-weight: var(--font-weight-medium);
}
.tracking-\[0\.18em\] {
--tw-tracking: 0.18em;
letter-spacing: 0.18em;
}
.text-background {
color: var(--background);
}
.text-foreground {
color: var(--foreground);
}
.text-neutral-950 {
color: var(--color-neutral-950);
}
.uppercase {
text-transform: uppercase;
}
.shadow-\[0_1px_2px_rgb\(0_0_0\/0\.05\)\,0_2px_6px_-3px_rgb\(0_0_0\/0\.07\)\,inset_0_-1px_0_rgb\(0_0_0\/0\.03\)\] {
--tw-shadow: 0 1px 2px var(--tw-shadow-color, rgb(0 0 0/0.05)), 0 2px 6px -3px var(--tw-shadow-color, rgb(0 0 0/0.07)), inset 0 -1px 0 var(--tw-shadow-color, rgb(0 0 0/0.03));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.transition {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.transition-colors {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
transition-duration: var(--tw-duration, var(--default-transition-duration));
}
.duration-150 {
--tw-duration: 150ms;
transition-duration: 150ms;
}
.outline-none {
--tw-outline-style: none;
outline-style: none;
}
.select-none {
-webkit-user-select: none;
user-select: none;
}
.\[--hatch\:color-mix\(in_oklab\,var\(--foreground\)_10\%\,transparent\)\] {
--hatch: var(--foreground);
@supports (color: color-mix(in lab, red, red)) {
--hatch: color-mix(in oklab,var(--foreground) 10%,transparent);
}
}
.focus-visible\:ring-2:focus-visible {
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
.focus-visible\:ring-ring:focus-visible {
--tw-ring-color: var(--ring);
}
.focus-visible\:ring-offset-2:focus-visible {
--tw-ring-offset-width: 2px;
--tw-ring-offset-shadow: var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
}
.focus-visible\:ring-offset-background:focus-visible {
--tw-ring-offset-color: var(--background);
}
.disabled\:cursor-not-allowed:disabled {
cursor: not-allowed;
}
.disabled\:opacity-50:disabled {
opacity: 50%;
}
.dark\:shadow-\[0_1px_2px_rgb\(0_0_0\/0\.4\)\,inset_0_1px_0_rgb\(255_255_255\/0\.05\)\]:where(.dark, .dark *) {
--tw-shadow: 0 1px 2px var(--tw-shadow-color, rgb(0 0 0/0.4)), inset 0 1px 0 var(--tw-shadow-color, rgb(255 255 255/0.05));
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
}
}
:root {
--background: #fff;
--foreground: #111;
--primary: #171717;
--primary-foreground: #fff;
--secondary: #eee;
--secondary-foreground: #171717;
--muted: #eee;
--muted-foreground: #666;
--accent: #eee;
--accent-foreground: #171717;
--border: #ddd;
--input: #ddd;
--ring: #777;
--destructive: #dc2626;
--destructive-foreground: #fff;
--popover: #fff;
--popover-foreground: #111;
--success: #15803d;
--success-foreground: #fff;
--radius: .625rem;
--hairline: 1px;
}
.dark {
--background: #090909;
--foreground: #fafafa;
--primary: #fafafa;
--primary-foreground: #171717;
--secondary: #262626;
--secondary-foreground: #fafafa;
--muted: #262626;
--muted-foreground: #a3a3a3;
--accent: #262626;
--accent-foreground: #fafafa;
--border: #333;
--input: #333;
--popover: #171717;
--popover-foreground: #fafafa;
}
:root {
--card: oklch(1 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--border: oklch(0.922 0 0);
--primary: oklch(0.205 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--radius: 0.625rem;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--chrome: oklch(0.967 0 0);
--brand: oklch(0.6 0.23 29);
--chart-background: oklch(1 0 0);
--chart-foreground: oklch(0.145 0.004 285);
--chart-foreground-muted: oklch(0.55 0.014 260);
--chart-line-primary: var(--chart-1);
--chart-line-secondary: var(--chart-2);
--chart-crosshair: oklch(0.4 0.1828 274.34);
--chart-grid: oklch(0.9 0 0);
--chart-brush-border: var(--chart-grid);
--chart-tooltip-background: oklch(0.21 0.006 285 / 0.8);
--chart-tooltip-foreground: oklch(0.985 0 0);
--chart-tooltip-muted: oklch(0.65 0.01 260);
--chart-marker-background: oklch(0.97 0.005 260);
--chart-marker-border: oklch(0.85 0.01 260);
--chart-marker-foreground: oklch(0.3 0.01 260);
--chart-label: oklch(0.45 0.01 260);
--chart-scale-01: oklch(0.98 0.003 106);
--chart-scale-02: oklch(0.92 0.008 106);
--chart-scale-03: oklch(0.82 0.015 106);
--chart-scale-04: oklch(0.68 0.02 106);
--chart-scale-05: oklch(0.55 0.025 106);
--chart-scale-pattern-color: oklch(0.96 0.005 106);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--chrome: oklch(0.18 0 0);
--card: oklch(0.205 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--border: oklch(1 0 0 / 10%);
--primary: oklch(0.922 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.87 0 0);
--chart-2: oklch(0.556 0 0);
--chart-3: oklch(0.439 0 0);
--chart-4: oklch(0.371 0 0);
--chart-5: oklch(0.269 0 0);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.922 0 0);
--sidebar-primary-foreground: oklch(0.205 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
--brand: oklch(0.66 0.23 32);
--chart-background: oklch(0.145 0 0);
--chart-foreground: oklch(0.45 0 0);
--chart-foreground-muted: oklch(0.65 0.01 260);
--chart-crosshair: oklch(0.45 0 0);
--chart-grid: oklch(0.25 0 0);
--chart-brush-border: var(--chart-grid);
--chart-marker-background: oklch(0.25 0.01 260);
--chart-marker-border: oklch(0.4 0.01 260);
--chart-marker-foreground: oklch(0.9 0 0);
--chart-label: oklch(0.75 0.01 260);
--chart-scale-01: oklch(0.28 0.03 270);
--chart-scale-02: oklch(0.38 0.04 270);
--chart-scale-03: oklch(0.48 0.05 270);
--chart-scale-04: oklch(0.58 0.06 270);
--chart-scale-05: oklch(0.68 0.07 270);
--chart-scale-pattern-color: oklch(0.145 0 0);
}
@keyframes docs-dot-swing {
0%, 100% {
transform: translateX(0) scale(1);
}
45% {
transform: translateX(-6px) scale(0.7);
}
}
@keyframes hell-flicker {
0%, 100% {
opacity: 1;
}
41% {
opacity: 0.7;
}
43% {
opacity: 1;
}
77% {
opacity: 0.85;
}
78% {
opacity: 1;
}
}
@keyframes lights-off {
0% {
opacity: 0;
}
15% {
opacity: 1;
}
30% {
opacity: 0.2;
}
45% {
opacity: 1;
}
60% {
opacity: 0.5;
}
70%, 100% {
opacity: 1;
}
}
@keyframes lights-on {
0% {
opacity: 1;
}
20% {
opacity: 0;
}
32% {
opacity: 1;
}
50% {
opacity: 0.1;
}
60% {
opacity: 0.9;
}
75%, 100% {
opacity: 0;
}
}
@keyframes lights-fade {
to {
opacity: 0;
}
}
@keyframes eyes-dim {
from {
opacity: 0;
}
}
@keyframes eyes-open {
from {
opacity: 0;
transform: scaleY(0.05);
}
}
@keyframes eyes-blink {
0%, 92%, 100% {
transform: none;
}
95% {
transform: scaleY(0.08);
}
}
@keyframes crack-life {
0% {
opacity: 0;
transform: scale(0.92);
}
4% {
opacity: 1;
transform: none;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes egg-wobble {
0%, 84%, 100% {
transform: none;
}
87% {
transform: rotate(-14deg);
}
90% {
transform: rotate(10deg);
}
93% {
transform: rotate(-6deg);
}
96% {
transform: rotate(3deg);
}
}
@keyframes page-glitch {
0% {
transform: none;
filter: none;
clip-path: none;
}
12% {
transform: translate(-6px, 2px) skewX(-2deg);
filter: hue-rotate(90deg) saturate(3);
}
24% {
transform: translate(5px, -1px);
filter: invert(1) hue-rotate(180deg);
clip-path: inset(18% 0 52% 0);
}
36% {
transform: none;
filter: contrast(2.2) saturate(0);
clip-path: none;
}
48% {
transform: translate(9px, 0) skewX(4deg);
filter: hue-rotate(-60deg);
clip-path: inset(0 0 70% 0);
}
60% {
transform: translate(-3px, 3px);
filter: none;
clip-path: inset(40% 0 20% 0);
}
72% {
transform: translate(2px, -4px) scaleY(1.02);
filter: saturate(4) contrast(1.4);
clip-path: none;
}
86% {
transform: translate(-8px, 0);
filter: invert(1);
clip-path: inset(62% 0 8% 0);
}
}
@keyframes glitch-label {
0% {
transform: translate(0, 0);
opacity: 1;
}
33% {
transform: translate(-4px, 2px);
opacity: 0.6;
}
66% {
transform: translate(5px, -2px);
opacity: 1;
}
}
@keyframes deleted-progress {
from {
width: 0;
}
to {
width: 100%;
}
}
@keyframes deleted-restore {
0%, 70% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes creeper-swell {
0% {
transform: scale(0.3) translateY(40px);
opacity: 0;
filter: none;
}
20% {
transform: scale(1);
opacity: 1;
}
45%, 65%, 85% {
filter: brightness(3) saturate(0);
}
55%, 75% {
filter: none;
}
100% {
transform: scale(1.35);
filter: brightness(4) saturate(0);
}
}
@keyframes creeper-flash {
from {
opacity: 0.85;
}
to {
opacity: 0;
}
}
@property --tw-border-style {
syntax: "*";
inherits: false;
initial-value: solid;
}
@property --tw-font-weight {
syntax: "*";
inherits: false;
}
@property --tw-tracking {
syntax: "*";
inherits: false;
}
@property --tw-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-inset-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-inset-shadow-color {
syntax: "*";
inherits: false;
}
@property --tw-inset-shadow-alpha {
syntax: "<percentage>";
inherits: false;
initial-value: 100%;
}
@property --tw-ring-color {
syntax: "*";
inherits: false;
}
@property --tw-ring-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-inset-ring-color {
syntax: "*";
inherits: false;
}
@property --tw-inset-ring-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-ring-inset {
syntax: "*";
inherits: false;
}
@property --tw-ring-offset-width {
syntax: "<length>";
inherits: false;
initial-value: 0px;
}
@property --tw-ring-offset-color {
syntax: "*";
inherits: false;
initial-value: #fff;
}
@property --tw-ring-offset-shadow {
syntax: "*";
inherits: false;
initial-value: 0 0 #0000;
}
@property --tw-duration {
syntax: "*";
inherits: false;
}
@layer properties {
@supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {
--tw-border-style: solid;
--tw-font-weight: initial;
--tw-tracking: initial;
--tw-shadow: 0 0 #0000;
--tw-shadow-color: initial;
--tw-shadow-alpha: 100%;
--tw-inset-shadow: 0 0 #0000;
--tw-inset-shadow-color: initial;
--tw-inset-shadow-alpha: 100%;
--tw-ring-color: initial;
--tw-ring-shadow: 0 0 #0000;
--tw-inset-ring-color: initial;
--tw-inset-ring-shadow: 0 0 #0000;
--tw-ring-inset: initial;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-offset-shadow: 0 0 #0000;
--tw-duration: initial;
}
}
}