Back to buttons
"use client";

import { useState } from "react";
import { motion, AnimatePresence } from "motion/react";
import { Heart } from "lucide-react";
import { cn } from "@/lib/utils";

const COLORS = [
  "bg-red-500",
  "bg-orange-400",
  "bg-yellow-400",
  "bg-rose-500",
  "bg-purple-500",
  "bg-blue-400",
  "bg-amber-400",
  "bg-fuchsia-500",
];

const COUNT = 12;
const CONFETTI = Array.from({ length: COUNT }, (_, i) => {
  const angle = -160 + (i / (COUNT - 1)) * 140;
  const rad = (angle * Math.PI) / 180;
  const dist = 55 + (i % 3) * 18;
  return {
    id: i,
    x: Math.cos(rad) * dist,
    y: Math.sin(rad) * dist,
    rotate: (i % 2 === 0 ? 1 : -1) * (100 + i * 18),
    color: COLORS[i % COLORS.length],
    w: i % 2 === 0 ? 8 : 6,
    h: i % 3 === 0 ? 6 : 4,
    dur: 0.68 + (i % 4) * 0.07,
  };
});

export default function AnimatedLikeButton() {
  const [liked, setLiked] = useState(false);
  const [count, setCount] = useState(128);
  const [clickKey, setClickKey] = useState(0);

  const handleClick = () => {
    const next = !liked;
    setLiked(next);
    setCount((c) => (next ? c + 1 : c - 1));
    setClickKey((k) => k + 1);
  };

  return (
    <div className="relative inline-flex items-center justify-center">
      {/* Confetti — outside the button so overflow-hidden doesn't clip it */}
      <AnimatePresence>
        {liked &&
          CONFETTI.map((p) => (
            <motion.span
              key={`${p.id}-${clickKey}`}
              className={cn("absolute rounded-sm pointer-events-none", p.color)}
              style={{
                width: p.w,
                height: p.h,
                left: "50%",
                top: "50%",
                marginLeft: -(p.w / 2),
                marginTop: -(p.h / 2),
              }}
              initial={{ x: 0, y: 0, rotate: 0, opacity: 1, scale: 1 }}
              animate={{
                x: p.x,
                y: [0, p.y * 0.6, p.y],
                rotate: p.rotate,
                opacity: [1, 1, 0],
                scale: 0.7,
              }}
              exit={{}}
              transition={{ duration: p.dur, ease: [0.22, 1, 0.36, 1] }}
            />
          ))}
      </AnimatePresence>

      <motion.button
        onClick={handleClick}
        whileHover={{ scale: 1.04 }}
        whileTap={{ scale: 0.93 }}
        transition={{ type: "spring", stiffness: 380, damping: 22 }}
        className="relative overflow-hidden inline-flex items-center gap-3 px-4 py-2 rounded-full border border-border bg-background text-sm font-medium select-none cursor-pointer"
      >
        {/* Ripple */}
        <AnimatePresence initial={false}>
          <motion.span
            key={clickKey}
            className="absolute w-5 h-5 rounded-full bg-red-500/25 pointer-events-none"
            style={{ left: 33, top: "50%", marginLeft: -10, marginTop: -10 }}
            initial={{ scale: 0, opacity: 1 }}
            animate={{ scale: 15, opacity: 0 }}
            exit={{}}
            transition={{
              scale: { duration: 1.1, ease: "easeOut" },
              opacity: { duration: 1.0, ease: "easeIn", delay: 0.1 },
            }}
          />
        </AnimatePresence>

        {/* Heart */}
        <motion.div
          key={`heart-${clickKey}`}
          animate={
            liked ? { scale: [1, 1.5, 0.84, 1.1, 1] } : { scale: [1, 0.84, 1] }
          }
          transition={{ duration: 0.4, ease: "easeOut" }}
        >
          <Heart
            className={cn(
              "size-4 transition-colors duration-300",
              liked ? "text-red-500" : "text-muted-foreground",
            )}
            fill={liked ? "currentColor" : "none"}
            strokeWidth={liked ? 0 : 1.75}
          />
        </motion.div>

        {/* Sliding count */}
        <div className="overflow-hidden h-5 flex items-center tabular-nums w-7">
          <AnimatePresence mode="wait" initial={false}>
            <motion.span
              key={count}
              initial={{ y: liked ? 14 : -14, opacity: 0 }}
              animate={{ y: 0, opacity: 1 }}
              exit={{ y: liked ? -14 : 14, opacity: 0 }}
              transition={{ duration: 0.18, ease: [0.2, 0, 0.2, 1] }}
              className="block text-muted-foreground"
            >
              {count.toLocaleString()}
            </motion.span>
          </AnimatePresence>
        </div>
      </motion.button>
    </div>
  );
}

Button 20 - Animated Like Button

By ShadcnSpace

Try the interaction, copy the React source files, or download the complete example.

About Button 20 - Animated Like Button

Button 20 - Animated Like Button is an animated React and Tailwind CSS button by ShadcnSpace. 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

components/shadcn-space/button/button-20.tsx

"use client";

import { useState } from "react";
import { motion, AnimatePresence } from "motion/react";
import { Heart } from "lucide-react";
import { cn } from "@/lib/utils";

const COLORS = [
  "bg-red-500",
  "bg-orange-400",
  "bg-yellow-400",
  "bg-rose-500",
  "bg-purple-500",
  "bg-blue-400",
  "bg-amber-400",
  "bg-fuchsia-500",
];

const COUNT = 12;
const CONFETTI = Array.from({ length: COUNT }, (_, i) => {
  const angle = -160 + (i / (COUNT - 1)) * 140;
  const rad = (angle * Math.PI) / 180;
  const dist = 55 + (i % 3) * 18;
  return {
    id: i,
    x: Math.cos(rad) * dist,
    y: Math.sin(rad) * dist,
    rotate: (i % 2 === 0 ? 1 : -1) * (100 + i * 18),
    color: COLORS[i % COLORS.length],
    w: i % 2 === 0 ? 8 : 6,
    h: i % 3 === 0 ? 6 : 4,
    dur: 0.68 + (i % 4) * 0.07,
  };
});

export default function AnimatedLikeButton() {
  const [liked, setLiked] = useState(false);
  const [count, setCount] = useState(128);
  const [clickKey, setClickKey] = useState(0);

  const handleClick = () => {
    const next = !liked;
    setLiked(next);
    setCount((c) => (next ? c + 1 : c - 1));
    setClickKey((k) => k + 1);
  };

  return (
    <div className="relative inline-flex items-center justify-center">
      {/* Confetti — outside the button so overflow-hidden doesn't clip it */}
      <AnimatePresence>
        {liked &&
          CONFETTI.map((p) => (
            <motion.span
              key={`${p.id}-${clickKey}`}
              className={cn("absolute rounded-sm pointer-events-none", p.color)}
              style={{
                width: p.w,
                height: p.h,
                left: "50%",
                top: "50%",
                marginLeft: -(p.w / 2),
                marginTop: -(p.h / 2),
              }}
              initial={{ x: 0, y: 0, rotate: 0, opacity: 1, scale: 1 }}
              animate={{
                x: p.x,
                y: [0, p.y * 0.6, p.y],
                rotate: p.rotate,
                opacity: [1, 1, 0],
                scale: 0.7,
              }}
              exit={{}}
              transition={{ duration: p.dur, ease: [0.22, 1, 0.36, 1] }}
            />
          ))}
      </AnimatePresence>

      <motion.button
        onClick={handleClick}
        whileHover={{ scale: 1.04 }}
        whileTap={{ scale: 0.93 }}
        transition={{ type: "spring", stiffness: 380, damping: 22 }}
        className="relative overflow-hidden inline-flex items-center gap-3 px-4 py-2 rounded-full border border-border bg-background text-sm font-medium select-none cursor-pointer"
      >
        {/* Ripple */}
        <AnimatePresence initial={false}>
          <motion.span
            key={clickKey}
            className="absolute w-5 h-5 rounded-full bg-red-500/25 pointer-events-none"
            style={{ left: 33, top: "50%", marginLeft: -10, marginTop: -10 }}
            initial={{ scale: 0, opacity: 1 }}
            animate={{ scale: 15, opacity: 0 }}
            exit={{}}
            transition={{
              scale: { duration: 1.1, ease: "easeOut" },
              opacity: { duration: 1.0, ease: "easeIn", delay: 0.1 },
            }}
          />
        </AnimatePresence>

        {/* Heart */}
        <motion.div
          key={`heart-${clickKey}`}
          animate={
            liked ? { scale: [1, 1.5, 0.84, 1.1, 1] } : { scale: [1, 0.84, 1] }
          }
          transition={{ duration: 0.4, ease: "easeOut" }}
        >
          <Heart
            className={cn(
              "size-4 transition-colors duration-300",
              liked ? "text-red-500" : "text-muted-foreground",
            )}
            fill={liked ? "currentColor" : "none"}
            strokeWidth={liked ? 0 : 1.75}
          />
        </motion.div>

        {/* Sliding count */}
        <div className="overflow-hidden h-5 flex items-center tabular-nums w-7">
          <AnimatePresence mode="wait" initial={false}>
            <motion.span
              key={count}
              initial={{ y: liked ? 14 : -14, opacity: 0 }}
              animate={{ y: 0, opacity: 1 }}
              exit={{ y: liked ? -14 : 14, opacity: 0 }}
              transition={{ duration: 0.18, ease: [0.2, 0, 0.2, 1] }}
              className="block text-muted-foreground"
            >
              {count.toLocaleString()}
            </motion.span>
          </AnimatePresence>
        </div>
      </motion.button>
    </div>
  );
}

lib/utils.ts

import { config } from "@/config";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

export function capitalize(str: string) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
type GroupBy<T, K extends keyof T> = Record<string, T[]>;

export function groupBy<T, K extends keyof T>(
  array: T[],
  key: K
): GroupBy<T, K> {
  return array.reduce((acc, item) => {
    const keyValue = String(item[key]);
    if (!acc[keyValue]) {
      acc[keyValue] = [];
    }
    acc[keyValue].push(item);
    return acc;
  }, {} as GroupBy<T, K>);
}

export function absoluteUrl(path: string) {
  return process.env.NODE_ENV === "development"
    ? `http://localhost:3000/${path}`
    : `${config.appUrl}/${path}`;
}

config.ts

export const config = {
  appUrl:
    process.env.NODE_ENV === "production"
      ? process.env.VERCEL_PROJECT_PRODUCTION_URL ??
      process.env.NEXT_PUBLIC_APP_URL!
      : "http://localhost:3000",
  social: {
    github: "https://github.com/shadcnspace/shadcnspace",
    twitter: "https://twitter.com/",
  },
};

demo.tsx

export { default as default } from "@/components/shadcn-space/button/button-20";

CSS

/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
  :root, :host {
    --font-sans: -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-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
      "Courier New", monospace;
    --color-red-500: oklch(63.7% 0.237 25.331);
    --color-orange-400: oklch(75% 0.183 55.934);
    --color-amber-400: oklch(82.8% 0.189 84.429);
    --color-yellow-400: oklch(85.2% 0.199 91.936);
    --color-blue-400: oklch(70.7% 0.165 254.624);
    --color-purple-500: oklch(62.7% 0.265 303.9);
    --color-fuchsia-500: oklch(66.7% 0.295 322.15);
    --color-rose-500: oklch(64.5% 0.246 16.439);
    --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-sans);
    --default-font-feature-settings: "cv02", "cv03", "cv04", "cv11";
    --default-mono-font-family: var(--font-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;
  }
  .block {
    display: block;
  }
  .flex {
    display: flex;
  }
  .inline-flex {
    display: inline-flex;
  }
  .size-4 {
    width: calc(var(--spacing) * 4);
    height: calc(var(--spacing) * 4);
  }
  .h-5 {
    height: calc(var(--spacing) * 5);
  }
  .w-5 {
    width: calc(var(--spacing) * 5);
  }
  .w-7 {
    width: calc(var(--spacing) * 7);
  }
  .cursor-pointer {
    cursor: pointer;
  }
  .items-center {
    align-items: center;
  }
  .justify-center {
    justify-content: center;
  }
  .gap-3 {
    gap: calc(var(--spacing) * 3);
  }
  .overflow-hidden {
    overflow: hidden;
  }
  .rounded-full {
    border-radius: calc(infinity * 1px);
  }
  .rounded-sm {
    border-radius: calc(var(--radius) - 4px);
  }
  .border {
    border-style: var(--tw-border-style);
    border-width: 1px;
  }
  .border-border {
    border-color: var(--border);
  }
  .bg-amber-400 {
    background-color: var(--color-amber-400);
  }
  .bg-background {
    background-color: var(--background);
  }
  .bg-blue-400 {
    background-color: var(--color-blue-400);
  }
  .bg-fuchsia-500 {
    background-color: var(--color-fuchsia-500);
  }
  .bg-orange-400 {
    background-color: var(--color-orange-400);
  }
  .bg-purple-500 {
    background-color: var(--color-purple-500);
  }
  .bg-red-500 {
    background-color: var(--color-red-500);
  }
  .bg-red-500\/25 {
    background-color: color-mix(in srgb, oklch(63.7% 0.237 25.331) 25%, transparent);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--color-red-500) 25%, transparent);
    }
  }
  .bg-rose-500 {
    background-color: var(--color-rose-500);
  }
  .bg-yellow-400 {
    background-color: var(--color-yellow-400);
  }
  .px-4 {
    padding-inline: calc(var(--spacing) * 4);
  }
  .py-2 {
    padding-block: calc(var(--spacing) * 2);
  }
  .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);
  }
  .text-muted-foreground {
    color: var(--muted-foreground);
  }
  .text-red-500 {
    color: var(--color-red-500);
  }
  .tabular-nums {
    --tw-numeric-spacing: tabular-nums;
    font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);
  }
  .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-300 {
    --tw-duration: 300ms;
    transition-duration: 300ms;
  }
  .select-none {
    -webkit-user-select: none;
    user-select: none;
  }
}
: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 {
  --radius: 0.5rem;
  --background: oklch(1 0 0);
  --foreground: oklch(0.1296 0.0274 261.69);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.1296 0.0274 261.69);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.1296 0.0274 261.69);
  --primary: oklch(0.1296 0.0274 261.69);
  --primary-foreground: oklch(0.9276 0.0058 264.53);
  --secondary: oklch(0.967 0.0029 264.54);
  --secondary-foreground: oklch(0.1296 0.0274 261.69);
  --muted: oklch(0.967 0.0029 264.54);
  --muted-foreground: oklch(0.4461 0.0263 256.8);
  --accent: oklch(0.967 0.0029 264.54);
  --accent-foreground: oklch(0.1296 0.0274 261.69);
  --destructive: oklch(0.6368 0.2078 25.33);
  --border: oklch(0.9276 0.0058 264.53);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.7137 0.0192 261.32);
  --chart-1: oklch(63.681% 0.20784 25.315);
  --chart-2: oklch(78.453% 0.13254 181.95);
  --chart-3: oklch(62.31% 0.1881 259.83);
  --chart-4: oklch(87.896% 0.15335 91.611);
  --chart-5: oklch(75.763% 0.15899 55.922);
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.1296 0.0274 261.69);
  --sidebar-primary: oklch(0.1296 0.0274 261.69);
  --sidebar-primary-foreground: oklch(0.9276 0.0058 264.53);
  --sidebar-accent: oklch(0.967 0.0029 264.54);
  --sidebar-accent-foreground: oklch(0.1296 0.0274 261.69);
  --sidebar-border: oklch(0.9276 0.0058 264.53);
  --sidebar-ring: oklch(0.7137 0.0192 261.32);
}
.dark {
  --background: oklch(0.1296 0.0274 261.69);
  --foreground: oklch(0.9276 0.0058 264.53);
  --card: oklch(0.1296 0.0274 261.69);
  --card-foreground: oklch(0.9276 0.0058 264.53);
  --popover: oklch(0.1296 0.0274 261.69);
  --popover-foreground: oklch(0.9276 0.0058 264.53);
  --primary: oklch(0.9276 0.0058 264.53);
  --primary-foreground: oklch(0.1296 0.0274 261.69);
  --secondary: oklch(0.3729 0.0306 259.73);
  --secondary-foreground: oklch(0.9276 0.0058 264.53);
  --muted: oklch(0.2781 0.0296 256.85);
  --muted-foreground: oklch(0.8717 0.0093 258.34);
  --accent: oklch(0.2781 0.0296 256.85);
  --accent-foreground: oklch(0.9276 0.0058 264.53);
  --destructive: oklch(0.6368 0.2078 25.33);
  --border: oklch(27.808% 0.02963 256.871 / 70%);
  --input: oklch(1 0 0 / 15%);
  --ring: oklch(0.4461 0.0263 256.8);
  --chart-1: oklch(63.681% 0.20784 25.315);
  --chart-2: oklch(78.453% 0.13254 181.95);
  --chart-3: oklch(62.31% 0.1881 259.83);
  --chart-4: oklch(87.896% 0.15335 91.611);
  --chart-5: oklch(75.763% 0.15899 55.922);
  --sidebar: oklch(0.205 0 0);
  --sidebar-foreground: oklch(0.9276 0.0058 264.53);
  --sidebar-primary: oklch(0.9276 0.0058 264.53);
  --sidebar-primary-foreground: oklch(0.1296 0.0274 261.69);
  --sidebar-accent: oklch(0.2781 0.0296 256.85);
  --sidebar-accent-foreground: oklch(0.9276 0.0058 264.53);
  --sidebar-border: var(--border);
  --sidebar-ring: oklch(0.4461 0.0263 256.8);
}
@property --tw-border-style {
  syntax: "*";
  inherits: false;
  initial-value: solid;
}
@property --tw-font-weight {
  syntax: "*";
  inherits: false;
}
@property --tw-ordinal {
  syntax: "*";
  inherits: false;
}
@property --tw-slashed-zero {
  syntax: "*";
  inherits: false;
}
@property --tw-numeric-figure {
  syntax: "*";
  inherits: false;
}
@property --tw-numeric-spacing {
  syntax: "*";
  inherits: false;
}
@property --tw-numeric-fraction {
  syntax: "*";
  inherits: false;
}
@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-ordinal: initial;
      --tw-slashed-zero: initial;
      --tw-numeric-figure: initial;
      --tw-numeric-spacing: initial;
      --tw-numeric-fraction: initial;
      --tw-duration: initial;
    }
  }
}