Back to buttons
"use client";

import { forwardRef, useState, type ComponentPropsWithoutRef } from "react";

import { cn } from "@/lib/cn";
import {Minus,Plus} from "lucide-react";

export type QuantityStepperButtonProps = Readonly<
  {
    value?: number;
    min?: number;
    max?: number;
    onChange?: (value: number) => void;
  } & Omit<ComponentPropsWithoutRef<"div">, "onChange">
>;

// Quantity stepper — minus, count, plus in one inline control.
export const QuantityStepperButton = forwardRef<
  HTMLDivElement,
  QuantityStepperButtonProps
>(
  (
    {
      className,
      value: defaultValue = 1,
      min = 0,
      max = 99,
      onChange,
      ...props
    },
    ref,
  ) => {
    const [value, setValue] = useState(defaultValue);

    const update = (next: number) => {
      const clamped = Math.min(max, Math.max(min, next));
      setValue(clamped);
      onChange?.(clamped);
    };

    // Raised key: layered drop shadows below, white bevel on top, shaded
    // bottom edge. Pressing sinks it and flips the shadows inward.
    const keyClass = cn(
      "group flex w-10 cursor-pointer items-center justify-center rounded-lg bg-neutral-50 text-neutral-600 transition-[box-shadow,color,transform,background-color] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)]",
      "shadow-[0_1px_1px_rgba(0,0,0,0.12),0_2px_3px_rgba(0,0,0,0.1),0_4px_8px_rgba(0,0,0,0.06),inset_0_1px_0_rgba(255,255,255,0.55),inset_0_-2px_3px_rgba(0,0,0,0.1),inset_1px_0_1px_rgba(255,255,255,0.25),inset_-1px_0_1px_rgba(255,255,255,0.25)]",
      "hover:text-neutral-900",
      "active:bg-neutral-100 active:shadow-[0_1px_1px_rgba(0,0,0,0.06),inset_0_1px_1px_rgba(0,0,0,0.06),inset_0_2px_3px_rgba(0,0,0,0.03),inset_0_-2px_3px_rgba(0,0,0,0.05)]",
      "disabled:cursor-default disabled:bg-transparent disabled:text-neutral-300 disabled:shadow-none",
    );

    // Soft cast shadow under the glyph — 3D lift, no hard outline rim.
    const iconClass = cn(
      "shrink-0 filter-[drop-shadow(0_1px_1px_rgba(0,0,0,0.22))_drop-shadow(0_2px_3px_rgba(0,0,0,0.12))]",
      "group-disabled:filter-none",
    );

    return (
      <div
        ref={ref}
        data-slot="quantity-stepper-button"
        className={cn(
          "inline-flex h-11 items-stretch gap-1 rounded-xl bg-neutral-100 p-1 font-sans text-sm font-medium select-none",
          "shadow-[inset_0_1px_2px_rgba(0,0,0,0.08),inset_0_2px_4px_rgba(0,0,0,0.05),inset_0_-2px_3px_rgba(0,0,0,0.06),0_1px_0_rgba(255,255,255,0.9)]",
          className,
        )}
        {...props}
      >
        <button
          type="button"
          aria-label="Decrease quantity"
          disabled={value <= min}
          onClick={() => update(value - 1)}
          className={keyClass}
        >
          <Minus
            size={15}
            strokeWidth={2.5}
            aria-hidden
            className={iconClass}
          />
        </button>

        <span
          className="flex min-w-10 items-center justify-center px-2 text-neutral-900 tabular-nums [text-shadow:0_1px_0_rgba(255,255,255,0.8)]"
          aria-live="polite"
        >
          {value}
        </span>

        <button
          type="button"
          aria-label="Increase quantity"
          disabled={value >= max}
          onClick={() => update(value + 1)}
          className={keyClass}
        >
          <Plus size={15} strokeWidth={2.5} aria-hidden className={iconClass} />
        </button>
      </div>
    );
  },
);

QuantityStepperButton.displayName = "QuantityStepperButton";

Quantity Stepper Button

By Bidyut

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

About Quantity Stepper Button

Quantity Stepper Button is an animated React and Tailwind CSS button by Bidyut. 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/quantity-stepper-button.tsx

import {QuantityStepperButton} from "@/components/buttons/quantity-stepper-button";
export default function Demo(){return (<QuantityStepperButton />);}

components/buttons/quantity-stepper-button.tsx

"use client";

import { forwardRef, useState, type ComponentPropsWithoutRef } from "react";

import { cn } from "@/lib/cn";
import {Minus,Plus} from "lucide-react";

export type QuantityStepperButtonProps = Readonly<
  {
    value?: number;
    min?: number;
    max?: number;
    onChange?: (value: number) => void;
  } & Omit<ComponentPropsWithoutRef<"div">, "onChange">
>;

// Quantity stepper — minus, count, plus in one inline control.
export const QuantityStepperButton = forwardRef<
  HTMLDivElement,
  QuantityStepperButtonProps
>(
  (
    {
      className,
      value: defaultValue = 1,
      min = 0,
      max = 99,
      onChange,
      ...props
    },
    ref,
  ) => {
    const [value, setValue] = useState(defaultValue);

    const update = (next: number) => {
      const clamped = Math.min(max, Math.max(min, next));
      setValue(clamped);
      onChange?.(clamped);
    };

    // Raised key: layered drop shadows below, white bevel on top, shaded
    // bottom edge. Pressing sinks it and flips the shadows inward.
    const keyClass = cn(
      "group flex w-10 cursor-pointer items-center justify-center rounded-lg bg-neutral-50 text-neutral-600 transition-[box-shadow,color,transform,background-color] duration-200 ease-[cubic-bezier(0.32,0.72,0,1)]",
      "shadow-[0_1px_1px_rgba(0,0,0,0.12),0_2px_3px_rgba(0,0,0,0.1),0_4px_8px_rgba(0,0,0,0.06),inset_0_1px_0_rgba(255,255,255,0.55),inset_0_-2px_3px_rgba(0,0,0,0.1),inset_1px_0_1px_rgba(255,255,255,0.25),inset_-1px_0_1px_rgba(255,255,255,0.25)]",
      "hover:text-neutral-900",
      "active:bg-neutral-100 active:shadow-[0_1px_1px_rgba(0,0,0,0.06),inset_0_1px_1px_rgba(0,0,0,0.06),inset_0_2px_3px_rgba(0,0,0,0.03),inset_0_-2px_3px_rgba(0,0,0,0.05)]",
      "disabled:cursor-default disabled:bg-transparent disabled:text-neutral-300 disabled:shadow-none",
    );

    // Soft cast shadow under the glyph — 3D lift, no hard outline rim.
    const iconClass = cn(
      "shrink-0 filter-[drop-shadow(0_1px_1px_rgba(0,0,0,0.22))_drop-shadow(0_2px_3px_rgba(0,0,0,0.12))]",
      "group-disabled:filter-none",
    );

    return (
      <div
        ref={ref}
        data-slot="quantity-stepper-button"
        className={cn(
          "inline-flex h-11 items-stretch gap-1 rounded-xl bg-neutral-100 p-1 font-sans text-sm font-medium select-none",
          "shadow-[inset_0_1px_2px_rgba(0,0,0,0.08),inset_0_2px_4px_rgba(0,0,0,0.05),inset_0_-2px_3px_rgba(0,0,0,0.06),0_1px_0_rgba(255,255,255,0.9)]",
          className,
        )}
        {...props}
      >
        <button
          type="button"
          aria-label="Decrease quantity"
          disabled={value <= min}
          onClick={() => update(value - 1)}
          className={keyClass}
        >
          <Minus
            size={15}
            strokeWidth={2.5}
            aria-hidden
            className={iconClass}
          />
        </button>

        <span
          className="flex min-w-10 items-center justify-center px-2 text-neutral-900 tabular-nums [text-shadow:0_1px_0_rgba(255,255,255,0.8)]"
          aria-live="polite"
        >
          {value}
        </span>

        <button
          type="button"
          aria-label="Increase quantity"
          disabled={value >= max}
          onClick={() => update(value + 1)}
          className={keyClass}
        >
          <Plus size={15} strokeWidth={2.5} aria-hidden className={iconClass} />
        </button>
      </div>
    );
  },
);

QuantityStepperButton.displayName = "QuantityStepperButton";

lib/cn.ts

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

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

demo.tsx


export { default as default } from "@/import-examples/quantity-stepper-button";

CSS

/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
  :root, :host {
    --font-sans: var(--font-geist-sans);
    --font-mono: var(--font-geist-mono), ui-monospace, SFMono-Regular, Menlo, Monaco,
    Consolas, monospace;
    --color-neutral-50: oklch(98.5% 0 none);
    --color-neutral-100: oklch(97% 0 none);
    --color-neutral-300: oklch(87% 0 none);
    --color-neutral-600: oklch(43.9% 0 none);
    --color-neutral-900: oklch(20.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-sans);
    --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 {
  .flex {
    display: flex;
  }
  .inline {
    display: inline;
  }
  .inline-flex {
    display: inline-flex;
  }
  .h-11 {
    height: calc(var(--spacing) * 11);
  }
  .w-10 {
    width: calc(var(--spacing) * 10);
  }
  .min-w-10 {
    min-width: calc(var(--spacing) * 10);
  }
  .shrink-0 {
    flex-shrink: 0;
  }
  .cursor-pointer {
    cursor: pointer;
  }
  .items-center {
    align-items: center;
  }
  .items-stretch {
    align-items: stretch;
  }
  .justify-center {
    justify-content: center;
  }
  .gap-1 {
    gap: var(--spacing);
  }
  .rounded-lg {
    border-radius: var(--radius);
  }
  .rounded-xl {
    border-radius: calc(var(--radius) + 4px);
  }
  .bg-neutral-50 {
    background-color: var(--color-neutral-50);
  }
  .bg-neutral-100 {
    background-color: var(--color-neutral-100);
  }
  .p-1 {
    padding: var(--spacing);
  }
  .px-2 {
    padding-inline: calc(var(--spacing) * 2);
  }
  .font-sans {
    font-family: var(--font-sans);
  }
  .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-neutral-600 {
    color: var(--color-neutral-600);
  }
  .text-neutral-900 {
    color: var(--color-neutral-900);
  }
  .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,);
  }
  .shadow {
    --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }
  .shadow-\[0_1px_1px_rgba\(0\,0\,0\,0\.12\)\,0_2px_3px_rgba\(0\,0\,0\,0\.1\)\,0_4px_8px_rgba\(0\,0\,0\,0\.06\)\,inset_0_1px_0_rgba\(255\,255\,255\,0\.55\)\,inset_0_-2px_3px_rgba\(0\,0\,0\,0\.1\)\,inset_1px_0_1px_rgba\(255\,255\,255\,0\.25\)\,inset_-1px_0_1px_rgba\(255\,255\,255\,0\.25\)\] {
    --tw-shadow: 0 1px 1px var(--tw-shadow-color, rgba(0,0,0,0.12)), 0 2px 3px var(--tw-shadow-color, rgba(0,0,0,0.1)), 0 4px 8px var(--tw-shadow-color, rgba(0,0,0,0.06)), inset 0 1px 0 var(--tw-shadow-color, rgba(255,255,255,0.55)), inset 0 -2px 3px var(--tw-shadow-color, rgba(0,0,0,0.1)), inset 1px 0 1px var(--tw-shadow-color, rgba(255,255,255,0.25)), inset -1px 0 1px var(--tw-shadow-color, rgba(255,255,255,0.25));
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }
  .shadow-\[inset_0_1px_2px_rgba\(0\,0\,0\,0\.08\)\,inset_0_2px_4px_rgba\(0\,0\,0\,0\.05\)\,inset_0_-2px_3px_rgba\(0\,0\,0\,0\.06\)\,0_1px_0_rgba\(255\,255\,255\,0\.9\)\] {
    --tw-shadow: inset 0 1px 2px var(--tw-shadow-color, rgba(0,0,0,0.08)), inset 0 2px 4px var(--tw-shadow-color, rgba(0,0,0,0.05)), inset 0 -2px 3px var(--tw-shadow-color, rgba(0,0,0,0.06)), 0 1px 0 var(--tw-shadow-color, rgba(255,255,255,0.9));
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }
  .outline {
    outline-style: var(--tw-outline-style);
    outline-width: 1px;
  }
  .filter-\[drop-shadow\(0_1px_1px_rgba\(0\,0\,0\,0\.22\)\)_drop-shadow\(0_2px_3px_rgba\(0\,0\,0\,0\.12\)\)\] {
    filter: drop-shadow(0 1px 1px rgba(0,0,0,0.22)) drop-shadow(0 2px 3px rgba(0,0,0,0.12));
  }
  .transition-\[box-shadow\,color\,transform\,background-color\] {
    transition-property: box-shadow,color,transform,background-color;
    transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
    transition-duration: var(--tw-duration, var(--default-transition-duration));
  }
  .duration-200 {
    --tw-duration: 200ms;
    transition-duration: 200ms;
  }
  .ease-\[cubic-bezier\(0\.32\,0\.72\,0\,1\)\] {
    --tw-ease: cubic-bezier(0.32,0.72,0,1);
    transition-timing-function: cubic-bezier(0.32,0.72,0,1);
  }
  .select-none {
    -webkit-user-select: none;
    user-select: none;
  }
  .\[text-shadow\:0_1px_0_rgba\(255\,255\,255\,0\.8\)\] {
    text-shadow: 0 1px 0 rgba(255,255,255,0.8);
  }
  .group-disabled\:filter-none:is(:where(.group):disabled *) {
    filter: none;
  }
  @media (hover: hover) {
    .hover\:text-neutral-900:hover {
      color: var(--color-neutral-900);
    }
  }
  .active\:bg-neutral-100:active {
    background-color: var(--color-neutral-100);
  }
  .active\:shadow-\[0_1px_1px_rgba\(0\,0\,0\,0\.06\)\,inset_0_1px_1px_rgba\(0\,0\,0\,0\.06\)\,inset_0_2px_3px_rgba\(0\,0\,0\,0\.03\)\,inset_0_-2px_3px_rgba\(0\,0\,0\,0\.05\)\]:active {
    --tw-shadow: 0 1px 1px var(--tw-shadow-color, rgba(0,0,0,0.06)), inset 0 1px 1px var(--tw-shadow-color, rgba(0,0,0,0.06)), inset 0 2px 3px var(--tw-shadow-color, rgba(0,0,0,0.03)), inset 0 -2px 3px var(--tw-shadow-color, rgba(0,0,0,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);
  }
  .disabled\:cursor-default:disabled {
    cursor: default;
  }
  .disabled\:bg-transparent:disabled {
    background-color: transparent;
  }
  .disabled\:text-neutral-300:disabled {
    color: var(--color-neutral-300);
  }
  .disabled\:shadow-none:disabled {
    --tw-shadow: 0 0 #0000;
    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;
}
@keyframes code-panel-shift {
  0%, 100% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
}
@keyframes caret-blink {
  0%, 49% {
    opacity: 1;
  }
  50%, 100% {
    opacity: 0;
  }
}
@keyframes wave-hand {
  0%, 100% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(-12deg);
  }
}
@keyframes marketing-go-back-in {
  from {
    opacity: 0;
    transform: translateX(-6px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}
@keyframes showcase-fade-in {
  from {
    opacity: 0;
    transform: translateY(3px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
@keyframes watch-ring-draw-outer {
  from {
    stroke-dasharray: 0 163;
  }
  to {
    stroke-dasharray: 121 163;
  }
}
@keyframes watch-ring-draw-middle {
  from {
    stroke-dasharray: 0 119;
  }
  to {
    stroke-dasharray: 74 119;
  }
}
@keyframes watch-ring-draw-inner {
  from {
    stroke-dasharray: 0 75;
  }
  to {
    stroke-dasharray: 66 75;
  }
}
@keyframes watch-brand-line {
  from {
    opacity: 0;
    transform: translateY(5px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
@keyframes showcase-progress {
  0% {
    transform: scaleX(0.12);
  }
  100% {
    transform: scaleX(0.96);
  }
}
@keyframes showcase-art-zoom {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.07);
  }
}
@keyframes ipod-bar {
  0%, 100% {
    transform: scaleY(0.28);
  }
  50% {
    transform: scaleY(1);
  }
}
@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-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-outline-style {
  syntax: "*";
  inherits: false;
  initial-value: solid;
}
@property --tw-duration {
  syntax: "*";
  inherits: false;
}
@property --tw-ease {
  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-font-weight: initial;
      --tw-ordinal: initial;
      --tw-slashed-zero: initial;
      --tw-numeric-figure: initial;
      --tw-numeric-spacing: initial;
      --tw-numeric-fraction: 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-outline-style: solid;
      --tw-duration: initial;
      --tw-ease: initial;
    }
  }
}