Back to buttons
"use client"

import { useEffect, useState, type CSSProperties } from "react"
import {
  motion,
  useReducedMotion,
  useSpring,
  useTransform,
} from "motion/react"

import { cn } from "@/lib/utils"

type RealisticSwitchSize = "sm" | "default" | "lg"
type RealisticSwitchTone = "auto" | "light" | "dark"

type RealisticSwitchProps = {
  checked?: boolean
  defaultChecked?: boolean
  onCheckedChange?: (checked: boolean) => void
  /** Cap color. Any CSS color; its walls, shading, and glow are mixed from it. */
  color?: string
  /** Color of the power mark on the cap. */
  markColor?: string
  /** Socket finish: follow the theme, or force ceramic white or graphite. */
  tone?: RealisticSwitchTone
  /** Light the cap from inside while it is latched on. */
  illuminated?: boolean
  /** Play a short mechanical click when it latches or releases. */
  sound?: boolean
  size?: RealisticSwitchSize
  disabled?: boolean
  className?: string
  "aria-label"?: string
}

// Everything is sized in em, so one font size scales the whole switch.
const FONT_SIZE: Record<RealisticSwitchSize, number> = {
  sm: 11,
  default: 15,
  lg: 19,
}

// Geometry, in em. The cap is a box standing on its own walls inside a
// recessed socket; its height above the socket floor is the one thing that
// moves. Cap and walls slide together on the same transform, and the walls are
// clipped at the floor, so nothing is resized and nothing snaps to a pixel.
const SOCKET = 4.4
const CAP = 3.3
const GAP = (SOCKET - CAP) / 2

// Cap height in each state: up, dipped under hover, fully pressed, and
// latched down while on.
const HEIGHT = {
  up: 0.95,
  hover: 0.82,
  pressed: 0.1,
  latched: 0.34,
  latchedHover: 0.3,
}

// A touch of bounce, so a released cap settles like a spring without wobbling
// through the small hover dip.
const SPRING = { stiffness: 520, damping: 30, mass: 0.6 }

const TONES: Record<RealisticSwitchTone, string> = {
  light:
    "[--hi:#ffffff] [--mid:#efeff2] [--lo:#d9d9df] [--well:#c9c9d1] [--well-lo:#aeaeb8] [--floor:rgb(20_20_40/0.35)] [--spill:0.35]",
  dark: "[--hi:#3a3a40] [--mid:#26262b] [--lo:#18181b] [--well:#0d0d10] [--well-lo:#050506] [--floor:rgb(0_0_0/0.8)] [--spill:0.6]",
  auto: "[--hi:#ffffff] [--mid:#efeff2] [--lo:#d9d9df] [--well:#c9c9d1] [--well-lo:#aeaeb8] [--floor:rgb(20_20_40/0.35)] [--spill:0.35] dark:[--hi:#3a3a40] dark:[--mid:#26262b] dark:[--lo:#18181b] dark:[--well:#0d0d10] dark:[--well-lo:#050506] dark:[--floor:rgb(0_0_0/0.8)] dark:[--spill:0.6]",
}

const mix = (amount: number, toward: "white" | "black") =>
  `color-mix(in oklab, var(--cap) ${amount}%, ${toward})`

const em = (value: number) => `${value}em`

let audio: AudioContext | null = null

// A switch click is a very short, bright burst of noise. Latching is pitched a
// little higher than releasing, like a real push switch's two stops.
function playClick(on: boolean) {
  try {
    audio ??= new AudioContext()
    const length = Math.floor(audio.sampleRate * 0.03)
    const buffer = audio.createBuffer(1, length, audio.sampleRate)
    const data = buffer.getChannelData(0)
    for (let i = 0; i < length; i++) {
      data[i] = (Math.random() * 2 - 1) * (1 - i / length) ** 6
    }
    const source = audio.createBufferSource()
    source.buffer = buffer
    const filter = audio.createBiquadFilter()
    filter.type = "bandpass"
    filter.frequency.value = on ? 3400 : 2500
    filter.Q.value = 1.1
    const gain = audio.createGain()
    gain.gain.value = 0.7
    source.connect(filter).connect(gain).connect(audio.destination)
    source.start()
  } catch {
    // No audio available: the switch still works silently.
  }
}

function RealisticSwitch({
  checked: checkedProp,
  defaultChecked = false,
  onCheckedChange,
  color = "#e1261c",
  markColor = "rgb(255 255 255 / 0.92)",
  tone = "auto",
  illuminated = true,
  sound = false,
  size = "default",
  disabled = false,
  className,
  "aria-label": ariaLabel = "Power",
}: RealisticSwitchProps) {
  const [internalChecked, setInternalChecked] = useState(defaultChecked)
  const isControlled = checkedProp !== undefined
  const checked = isControlled ? checkedProp : internalChecked
  const [pressing, setPressing] = useState(false)
  const [hovering, setHovering] = useState(false)
  const reduceMotion = useReducedMotion()

  const target = pressing
    ? HEIGHT.pressed
    : checked
      ? hovering
        ? HEIGHT.latchedHover
        : HEIGHT.latched
      : hovering
        ? HEIGHT.hover
        : HEIGHT.up
  const height = useSpring(target, SPRING)

  useEffect(() => {
    if (reduceMotion) height.jump(target)
    else height.set(target)
  }, [height, target, reduceMotion])

  // The walls fill the space under the cap, and the cast shadow spreads and
  // fades as the cap rises away from the socket floor.
  const capLift = useTransform(height, (h) => em(-h))
  const shadowOpacity = useTransform(height, [0, HEIGHT.up], [0.35, 1])
  const shadowScale = useTransform(height, [0, HEIGHT.up], [0.92, 1.06])
  const shadowDrop = useTransform(height, (h) => em(0.05 + h * 0.35))

  const toggle = () => {
    const next = !checked
    if (!isControlled) {
      setInternalChecked(next)
    }
    onCheckedChange?.(next)
    if (sound) {
      playClick(next)
    }
  }

  const lit = illuminated && checked

  return (
    <button
      type="button"
      role="switch"
      aria-checked={checked}
      aria-label={ariaLabel}
      disabled={disabled}
      onClick={toggle}
      onPointerDown={(e) => {
        if (e.button === 0) setPressing(true)
      }}
      onPointerUp={() => setPressing(false)}
      onPointerEnter={(e) => {
        if (e.pointerType === "mouse") setHovering(true)
      }}
      onPointerLeave={() => {
        setPressing(false)
        setHovering(false)
      }}
      onPointerCancel={() => setPressing(false)}
      onKeyDown={(e) => {
        if (e.key === " " || e.key === "Enter") setPressing(true)
      }}
      onKeyUp={() => setPressing(false)}
      onBlur={() => setPressing(false)}
      style={{ fontSize: FONT_SIZE[size], "--cap": color } as CSSProperties}
      className={cn(
        "group relative inline-flex cursor-pointer rounded-[1.1em] p-[0.5em] pt-[1.4em] outline-none select-none [-webkit-tap-highlight-color:transparent]",
        "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",
        TONES[tone],
        className
      )}
    >
      <span
        aria-hidden
        className="relative block"
        style={{ width: em(SOCKET), height: em(SOCKET) }}
      >
        {/* Socket: a moulded plate with a lit top edge and a soft drop shadow. */}
        <span
          className="absolute -inset-[0.3em] rounded-[1.05em] shadow-[0_0.08em_0.1em_rgb(0_0_0/0.18),0_0.5em_1em_-0.3em_var(--floor),inset_0_0.05em_0_rgb(255_255_255/0.6),inset_0_-0.06em_0_rgb(0_0_0/0.18)]"
          style={{ background: "linear-gradient(to bottom, var(--hi), var(--mid) 50%, var(--lo))" }}
        />
        {/* The well the cap travels in: darker the deeper it goes. */}
        <span
          className="absolute inset-0 rounded-[0.85em] shadow-[inset_0_0.14em_0.3em_rgb(0_0_0/0.5),inset_0_-0.04em_0_rgb(255_255_255/0.25),0_0.04em_0_rgb(255_255_255/0.5)]"
          style={{ background: "linear-gradient(to bottom, var(--well-lo), var(--well))" }}
        />
        {/* Light from a latched cap pooling in the well. */}
        <span
          className="absolute inset-[0.15em] rounded-[0.75em] blur-[0.35em] transition-opacity duration-500"
          style={{ background: "var(--cap)", opacity: lit ? "var(--spill)" : 0 }}
        />
        {/* Shadow the cap casts on the well floor. */}
        <motion.span
          className="absolute rounded-[0.7em] bg-black/70 blur-[0.3em]"
          style={{
            inset: em(GAP),
            opacity: shadowOpacity,
            scale: shadowScale,
            y: shadowDrop,
          }}
        />
        {/* Walls: a block that rides up with the cap, cut off at the floor. */}
        <span
          className="absolute overflow-hidden rounded-b-[0.7em]"
          style={{ left: em(GAP), right: em(GAP), bottom: em(GAP), top: em(-HEIGHT.up) }}
        >
          <motion.span
            className="absolute inset-x-0 overflow-hidden rounded-[0.7em] will-change-transform"
            style={{
              // Starts level with the cap's top and reaches the floor even at full lift.
              top: em(GAP + HEIGHT.up),
              height: em(CAP + HEIGHT.up),
              y: capLift,
              background: `linear-gradient(to bottom, ${mix(62, "black")}, ${mix(40, "black")})`,
            }}
          >
            {/* Rounded corners turn away from the light at both sides. */}
            <span className="absolute inset-0 bg-[linear-gradient(to_right,rgb(0_0_0/0.35),transparent_18%,rgb(255_255_255/0.08)_50%,transparent_82%,rgb(0_0_0/0.35))]" />
          </motion.span>
        </span>
        {/* Cap: the top face, carried up by the walls. */}
        <motion.span
          className="absolute overflow-hidden rounded-[0.7em] will-change-transform"
          style={{
            left: em(GAP),
            top: em(GAP),
            width: em(CAP),
            height: em(CAP),
            y: capLift,
            background: `linear-gradient(to bottom, ${mix(80, "white")}, var(--cap) 45%, ${mix(86, "black")})`,
            boxShadow: `inset 0 0.06em 0 ${mix(45, "white")}, inset 0 -0.08em 0.05em ${mix(60, "black")}`,
          }}
        >
          {/* A shallow dish in the middle of the cap, lit from above. */}
          <span
            className="absolute inset-[0.34em] rounded-[0.5em]"
            style={{
              background: `linear-gradient(to bottom, ${mix(82, "black")}, ${mix(92, "white")})`,
              boxShadow: `inset 0 0.07em 0.12em ${mix(45, "black")}, 0 0.04em 0 ${mix(55, "white")}`,
            }}
          />
          {/* Inner lamp: the cap glows through when latched on. */}
          <span
            className="absolute inset-0 transition-opacity duration-500"
            style={{
              opacity: lit ? 1 : 0,
              background:
                "radial-gradient(circle at 50% 50%, rgb(255 240 225 / 0.55), rgb(255 200 170 / 0.18) 50%, transparent 80%)",
            }}
          />
          <svg
            viewBox="0 0 24 24"
            fill="none"
            strokeWidth={2.4}
            strokeLinecap="round"
            className="absolute top-1/2 left-1/2 size-[1.25em] -translate-x-1/2 -translate-y-1/2 transition-[filter] duration-500"
            style={{
              stroke: markColor,
              filter: lit
                ? "drop-shadow(0 0 0.12em rgb(255 255 255 / 0.9))"
                : "drop-shadow(0 0.04em 0 rgb(0 0 0 / 0.35))",
            }}
          >
            <path d="M12 3v8" />
            <path d="M7.05 6.4a7 7 0 1 0 9.9 0" />
          </svg>
        </motion.span>
      </span>
    </button>
  )
}

export { RealisticSwitch }
export type { RealisticSwitchProps, RealisticSwitchSize, RealisticSwitchTone }

RealisticSwitch

By jay sharma

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

About RealisticSwitch

RealisticSwitch 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/realistic-switch.tsx

import { RealisticSwitch } from "@/components/evil-buttons/realistic-switch";

export function PowerSwitch() {
  return (
    <RealisticSwitch
      sound
      aria-label="Main power"
      onCheckedChange={(on) => console.log("power:", on)}
    />
  );
}

components/evil-buttons/realistic-switch.tsx

"use client"

import { useEffect, useState, type CSSProperties } from "react"
import {
  motion,
  useReducedMotion,
  useSpring,
  useTransform,
} from "motion/react"

import { cn } from "@/lib/utils"

type RealisticSwitchSize = "sm" | "default" | "lg"
type RealisticSwitchTone = "auto" | "light" | "dark"

type RealisticSwitchProps = {
  checked?: boolean
  defaultChecked?: boolean
  onCheckedChange?: (checked: boolean) => void
  /** Cap color. Any CSS color; its walls, shading, and glow are mixed from it. */
  color?: string
  /** Color of the power mark on the cap. */
  markColor?: string
  /** Socket finish: follow the theme, or force ceramic white or graphite. */
  tone?: RealisticSwitchTone
  /** Light the cap from inside while it is latched on. */
  illuminated?: boolean
  /** Play a short mechanical click when it latches or releases. */
  sound?: boolean
  size?: RealisticSwitchSize
  disabled?: boolean
  className?: string
  "aria-label"?: string
}

// Everything is sized in em, so one font size scales the whole switch.
const FONT_SIZE: Record<RealisticSwitchSize, number> = {
  sm: 11,
  default: 15,
  lg: 19,
}

// Geometry, in em. The cap is a box standing on its own walls inside a
// recessed socket; its height above the socket floor is the one thing that
// moves. Cap and walls slide together on the same transform, and the walls are
// clipped at the floor, so nothing is resized and nothing snaps to a pixel.
const SOCKET = 4.4
const CAP = 3.3
const GAP = (SOCKET - CAP) / 2

// Cap height in each state: up, dipped under hover, fully pressed, and
// latched down while on.
const HEIGHT = {
  up: 0.95,
  hover: 0.82,
  pressed: 0.1,
  latched: 0.34,
  latchedHover: 0.3,
}

// A touch of bounce, so a released cap settles like a spring without wobbling
// through the small hover dip.
const SPRING = { stiffness: 520, damping: 30, mass: 0.6 }

const TONES: Record<RealisticSwitchTone, string> = {
  light:
    "[--hi:#ffffff] [--mid:#efeff2] [--lo:#d9d9df] [--well:#c9c9d1] [--well-lo:#aeaeb8] [--floor:rgb(20_20_40/0.35)] [--spill:0.35]",
  dark: "[--hi:#3a3a40] [--mid:#26262b] [--lo:#18181b] [--well:#0d0d10] [--well-lo:#050506] [--floor:rgb(0_0_0/0.8)] [--spill:0.6]",
  auto: "[--hi:#ffffff] [--mid:#efeff2] [--lo:#d9d9df] [--well:#c9c9d1] [--well-lo:#aeaeb8] [--floor:rgb(20_20_40/0.35)] [--spill:0.35] dark:[--hi:#3a3a40] dark:[--mid:#26262b] dark:[--lo:#18181b] dark:[--well:#0d0d10] dark:[--well-lo:#050506] dark:[--floor:rgb(0_0_0/0.8)] dark:[--spill:0.6]",
}

const mix = (amount: number, toward: "white" | "black") =>
  `color-mix(in oklab, var(--cap) ${amount}%, ${toward})`

const em = (value: number) => `${value}em`

let audio: AudioContext | null = null

// A switch click is a very short, bright burst of noise. Latching is pitched a
// little higher than releasing, like a real push switch's two stops.
function playClick(on: boolean) {
  try {
    audio ??= new AudioContext()
    const length = Math.floor(audio.sampleRate * 0.03)
    const buffer = audio.createBuffer(1, length, audio.sampleRate)
    const data = buffer.getChannelData(0)
    for (let i = 0; i < length; i++) {
      data[i] = (Math.random() * 2 - 1) * (1 - i / length) ** 6
    }
    const source = audio.createBufferSource()
    source.buffer = buffer
    const filter = audio.createBiquadFilter()
    filter.type = "bandpass"
    filter.frequency.value = on ? 3400 : 2500
    filter.Q.value = 1.1
    const gain = audio.createGain()
    gain.gain.value = 0.7
    source.connect(filter).connect(gain).connect(audio.destination)
    source.start()
  } catch {
    // No audio available: the switch still works silently.
  }
}

function RealisticSwitch({
  checked: checkedProp,
  defaultChecked = false,
  onCheckedChange,
  color = "#e1261c",
  markColor = "rgb(255 255 255 / 0.92)",
  tone = "auto",
  illuminated = true,
  sound = false,
  size = "default",
  disabled = false,
  className,
  "aria-label": ariaLabel = "Power",
}: RealisticSwitchProps) {
  const [internalChecked, setInternalChecked] = useState(defaultChecked)
  const isControlled = checkedProp !== undefined
  const checked = isControlled ? checkedProp : internalChecked
  const [pressing, setPressing] = useState(false)
  const [hovering, setHovering] = useState(false)
  const reduceMotion = useReducedMotion()

  const target = pressing
    ? HEIGHT.pressed
    : checked
      ? hovering
        ? HEIGHT.latchedHover
        : HEIGHT.latched
      : hovering
        ? HEIGHT.hover
        : HEIGHT.up
  const height = useSpring(target, SPRING)

  useEffect(() => {
    if (reduceMotion) height.jump(target)
    else height.set(target)
  }, [height, target, reduceMotion])

  // The walls fill the space under the cap, and the cast shadow spreads and
  // fades as the cap rises away from the socket floor.
  const capLift = useTransform(height, (h) => em(-h))
  const shadowOpacity = useTransform(height, [0, HEIGHT.up], [0.35, 1])
  const shadowScale = useTransform(height, [0, HEIGHT.up], [0.92, 1.06])
  const shadowDrop = useTransform(height, (h) => em(0.05 + h * 0.35))

  const toggle = () => {
    const next = !checked
    if (!isControlled) {
      setInternalChecked(next)
    }
    onCheckedChange?.(next)
    if (sound) {
      playClick(next)
    }
  }

  const lit = illuminated && checked

  return (
    <button
      type="button"
      role="switch"
      aria-checked={checked}
      aria-label={ariaLabel}
      disabled={disabled}
      onClick={toggle}
      onPointerDown={(e) => {
        if (e.button === 0) setPressing(true)
      }}
      onPointerUp={() => setPressing(false)}
      onPointerEnter={(e) => {
        if (e.pointerType === "mouse") setHovering(true)
      }}
      onPointerLeave={() => {
        setPressing(false)
        setHovering(false)
      }}
      onPointerCancel={() => setPressing(false)}
      onKeyDown={(e) => {
        if (e.key === " " || e.key === "Enter") setPressing(true)
      }}
      onKeyUp={() => setPressing(false)}
      onBlur={() => setPressing(false)}
      style={{ fontSize: FONT_SIZE[size], "--cap": color } as CSSProperties}
      className={cn(
        "group relative inline-flex cursor-pointer rounded-[1.1em] p-[0.5em] pt-[1.4em] outline-none select-none [-webkit-tap-highlight-color:transparent]",
        "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",
        TONES[tone],
        className
      )}
    >
      <span
        aria-hidden
        className="relative block"
        style={{ width: em(SOCKET), height: em(SOCKET) }}
      >
        {/* Socket: a moulded plate with a lit top edge and a soft drop shadow. */}
        <span
          className="absolute -inset-[0.3em] rounded-[1.05em] shadow-[0_0.08em_0.1em_rgb(0_0_0/0.18),0_0.5em_1em_-0.3em_var(--floor),inset_0_0.05em_0_rgb(255_255_255/0.6),inset_0_-0.06em_0_rgb(0_0_0/0.18)]"
          style={{ background: "linear-gradient(to bottom, var(--hi), var(--mid) 50%, var(--lo))" }}
        />
        {/* The well the cap travels in: darker the deeper it goes. */}
        <span
          className="absolute inset-0 rounded-[0.85em] shadow-[inset_0_0.14em_0.3em_rgb(0_0_0/0.5),inset_0_-0.04em_0_rgb(255_255_255/0.25),0_0.04em_0_rgb(255_255_255/0.5)]"
          style={{ background: "linear-gradient(to bottom, var(--well-lo), var(--well))" }}
        />
        {/* Light from a latched cap pooling in the well. */}
        <span
          className="absolute inset-[0.15em] rounded-[0.75em] blur-[0.35em] transition-opacity duration-500"
          style={{ background: "var(--cap)", opacity: lit ? "var(--spill)" : 0 }}
        />
        {/* Shadow the cap casts on the well floor. */}
        <motion.span
          className="absolute rounded-[0.7em] bg-black/70 blur-[0.3em]"
          style={{
            inset: em(GAP),
            opacity: shadowOpacity,
            scale: shadowScale,
            y: shadowDrop,
          }}
        />
        {/* Walls: a block that rides up with the cap, cut off at the floor. */}
        <span
          className="absolute overflow-hidden rounded-b-[0.7em]"
          style={{ left: em(GAP), right: em(GAP), bottom: em(GAP), top: em(-HEIGHT.up) }}
        >
          <motion.span
            className="absolute inset-x-0 overflow-hidden rounded-[0.7em] will-change-transform"
            style={{
              // Starts level with the cap's top and reaches the floor even at full lift.
              top: em(GAP + HEIGHT.up),
              height: em(CAP + HEIGHT.up),
              y: capLift,
              background: `linear-gradient(to bottom, ${mix(62, "black")}, ${mix(40, "black")})`,
            }}
          >
            {/* Rounded corners turn away from the light at both sides. */}
            <span className="absolute inset-0 bg-[linear-gradient(to_right,rgb(0_0_0/0.35),transparent_18%,rgb(255_255_255/0.08)_50%,transparent_82%,rgb(0_0_0/0.35))]" />
          </motion.span>
        </span>
        {/* Cap: the top face, carried up by the walls. */}
        <motion.span
          className="absolute overflow-hidden rounded-[0.7em] will-change-transform"
          style={{
            left: em(GAP),
            top: em(GAP),
            width: em(CAP),
            height: em(CAP),
            y: capLift,
            background: `linear-gradient(to bottom, ${mix(80, "white")}, var(--cap) 45%, ${mix(86, "black")})`,
            boxShadow: `inset 0 0.06em 0 ${mix(45, "white")}, inset 0 -0.08em 0.05em ${mix(60, "black")}`,
          }}
        >
          {/* A shallow dish in the middle of the cap, lit from above. */}
          <span
            className="absolute inset-[0.34em] rounded-[0.5em]"
            style={{
              background: `linear-gradient(to bottom, ${mix(82, "black")}, ${mix(92, "white")})`,
              boxShadow: `inset 0 0.07em 0.12em ${mix(45, "black")}, 0 0.04em 0 ${mix(55, "white")}`,
            }}
          />
          {/* Inner lamp: the cap glows through when latched on. */}
          <span
            className="absolute inset-0 transition-opacity duration-500"
            style={{
              opacity: lit ? 1 : 0,
              background:
                "radial-gradient(circle at 50% 50%, rgb(255 240 225 / 0.55), rgb(255 200 170 / 0.18) 50%, transparent 80%)",
            }}
          />
          <svg
            viewBox="0 0 24 24"
            fill="none"
            strokeWidth={2.4}
            strokeLinecap="round"
            className="absolute top-1/2 left-1/2 size-[1.25em] -translate-x-1/2 -translate-y-1/2 transition-[filter] duration-500"
            style={{
              stroke: markColor,
              filter: lit
                ? "drop-shadow(0 0 0.12em rgb(255 255 255 / 0.9))"
                : "drop-shadow(0 0.04em 0 rgb(0 0 0 / 0.35))",
            }}
          >
            <path d="M12 3v8" />
            <path d="M7.05 6.4a7 7 0 1 0 9.9 0" />
          </svg>
        </motion.span>
      </span>
    </button>
  )
}

export { RealisticSwitch }
export type { RealisticSwitchProps, RealisticSwitchSize, RealisticSwitchTone }

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 { PowerSwitch as default } from "@/import-examples/realistic-switch";

CSS

/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@layer properties;
@layer theme, base, components, utilities;
@layer theme {
  :root, :host {
    --color-black: #000;
    --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 {
  .absolute {
    position: absolute;
  }
  .relative {
    position: relative;
  }
  .-inset-\[0\.3em\] {
    inset: calc(0.3em * -1);
  }
  .inset-0 {
    inset: 0px;
  }
  .inset-\[0\.15em\] {
    inset: 0.15em;
  }
  .inset-\[0\.34em\] {
    inset: 0.34em;
  }
  .inset-x-0 {
    inset-inline: 0px;
  }
  .top-1\/2 {
    top: calc(1 / 2 * 100%);
  }
  .left-1\/2 {
    left: calc(1 / 2 * 100%);
  }
  .block {
    display: block;
  }
  .inline-flex {
    display: inline-flex;
  }
  .size-\[1\.25em\] {
    width: 1.25em;
    height: 1.25em;
  }
  .-translate-x-1\/2 {
    --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
    translate: var(--tw-translate-x) var(--tw-translate-y);
  }
  .-translate-y-1\/2 {
    --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
    translate: var(--tw-translate-x) var(--tw-translate-y);
  }
  .cursor-pointer {
    cursor: pointer;
  }
  .overflow-hidden {
    overflow: hidden;
  }
  .rounded-\[0\.5em\] {
    border-radius: 0.5em;
  }
  .rounded-\[0\.7em\] {
    border-radius: 0.7em;
  }
  .rounded-\[0\.75em\] {
    border-radius: 0.75em;
  }
  .rounded-\[0\.85em\] {
    border-radius: 0.85em;
  }
  .rounded-\[1\.1em\] {
    border-radius: 1.1em;
  }
  .rounded-\[1\.05em\] {
    border-radius: 1.05em;
  }
  .rounded-b-\[0\.7em\] {
    border-bottom-right-radius: 0.7em;
    border-bottom-left-radius: 0.7em;
  }
  .bg-black\/70 {
    background-color: color-mix(in srgb, #000 70%, transparent);
    @supports (color: color-mix(in lab, red, red)) {
      background-color: color-mix(in oklab, var(--color-black) 70%, transparent);
    }
  }
  .bg-\[linear-gradient\(to_right\,rgb\(0_0_0\/0\.35\)\,transparent_18\%\,rgb\(255_255_255\/0\.08\)_50\%\,transparent_82\%\,rgb\(0_0_0\/0\.35\)\)\] {
    background-image: linear-gradient(to right,rgb(0 0 0/0.35),transparent 18%,rgb(255 255 255/0.08) 50%,transparent 82%,rgb(0 0 0/0.35));
  }
  .p-\[0\.5em\] {
    padding: 0.5em;
  }
  .pt-\[1\.4em\] {
    padding-top: 1.4em;
  }
  .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_0\.08em_0\.1em_rgb\(0_0_0\/0\.18\)\,0_0\.5em_1em_-0\.3em_var\(--floor\)\,inset_0_0\.05em_0_rgb\(255_255_255\/0\.6\)\,inset_0_-0\.06em_0_rgb\(0_0_0\/0\.18\)\] {
    --tw-shadow: 0 0.08em 0.1em var(--tw-shadow-color, rgb(0 0 0/0.18)), 0 0.5em 1em -0.3em var(--tw-shadow-color, var(--floor)), inset 0 0.05em 0 var(--tw-shadow-color, rgb(255 255 255/0.6)), inset 0 -0.06em 0 var(--tw-shadow-color, rgb(0 0 0/0.18));
    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_0\.14em_0\.3em_rgb\(0_0_0\/0\.5\)\,inset_0_-0\.04em_0_rgb\(255_255_255\/0\.25\)\,0_0\.04em_0_rgb\(255_255_255\/0\.5\)\] {
    --tw-shadow: inset 0 0.14em 0.3em var(--tw-shadow-color, rgb(0 0 0/0.5)), inset 0 -0.04em 0 var(--tw-shadow-color, rgb(255 255 255/0.25)), 0 0.04em 0 var(--tw-shadow-color, rgb(255 255 255/0.5));
    box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
  }
  .blur-\[0\.3em\] {
    --tw-blur: blur(0.3em);
    filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
  }
  .blur-\[0\.35em\] {
    --tw-blur: blur(0.35em);
    filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
  }
  .filter {
    filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
  }
  .transition-\[filter\] {
    transition-property: filter;
    transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
    transition-duration: var(--tw-duration, var(--default-transition-duration));
  }
  .transition-opacity {
    transition-property: opacity;
    transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
    transition-duration: var(--tw-duration, var(--default-transition-duration));
  }
  .duration-500 {
    --tw-duration: 500ms;
    transition-duration: 500ms;
  }
  .will-change-transform {
    will-change: transform;
  }
  .outline-none {
    --tw-outline-style: none;
    outline-style: none;
  }
  .select-none {
    -webkit-user-select: none;
    user-select: none;
  }
  .\[--floor\:rgb\(0_0_0\/0\.8\)\] {
    --floor: rgb(0 0 0/0.8);
  }
  .\[--floor\:rgb\(20_20_40\/0\.35\)\] {
    --floor: rgb(20 20 40/0.35);
  }
  .\[--hi\:\#3a3a40\] {
    --hi: #3a3a40;
  }
  .\[--hi\:\#ffffff\] {
    --hi: #ffffff;
  }
  .\[--lo\:\#18181b\] {
    --lo: #18181b;
  }
  .\[--lo\:\#d9d9df\] {
    --lo: #d9d9df;
  }
  .\[--mid\:\#26262b\] {
    --mid: #26262b;
  }
  .\[--mid\:\#efeff2\] {
    --mid: #efeff2;
  }
  .\[--spill\:0\.6\] {
    --spill: 0.6;
  }
  .\[--spill\:0\.35\] {
    --spill: 0.35;
  }
  .\[--well-lo\:\#050506\] {
    --well-lo: #050506;
  }
  .\[--well-lo\:\#aeaeb8\] {
    --well-lo: #aeaeb8;
  }
  .\[--well\:\#0d0d10\] {
    --well: #0d0d10;
  }
  .\[--well\:\#c9c9d1\] {
    --well: #c9c9d1;
  }
  .\[-webkit-tap-highlight-color\:transparent\] {
    -webkit-tap-highlight-color: 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\:\[--floor\:rgb\(0_0_0\/0\.8\)\]:where(.dark, .dark *) {
    --floor: rgb(0 0 0/0.8);
  }
  .dark\:\[--hi\:\#3a3a40\]:where(.dark, .dark *) {
    --hi: #3a3a40;
  }
  .dark\:\[--lo\:\#18181b\]:where(.dark, .dark *) {
    --lo: #18181b;
  }
  .dark\:\[--mid\:\#26262b\]:where(.dark, .dark *) {
    --mid: #26262b;
  }
  .dark\:\[--spill\:0\.6\]:where(.dark, .dark *) {
    --spill: 0.6;
  }
  .dark\:\[--well-lo\:\#050506\]:where(.dark, .dark *) {
    --well-lo: #050506;
  }
  .dark\:\[--well\:\#0d0d10\]:where(.dark, .dark *) {
    --well: #0d0d10;
  }
}
: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-translate-x {
  syntax: "*";
  inherits: false;
  initial-value: 0;
}
@property --tw-translate-y {
  syntax: "*";
  inherits: false;
  initial-value: 0;
}
@property --tw-translate-z {
  syntax: "*";
  inherits: false;
  initial-value: 0;
}
@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-blur {
  syntax: "*";
  inherits: false;
}
@property --tw-brightness {
  syntax: "*";
  inherits: false;
}
@property --tw-contrast {
  syntax: "*";
  inherits: false;
}
@property --tw-grayscale {
  syntax: "*";
  inherits: false;
}
@property --tw-hue-rotate {
  syntax: "*";
  inherits: false;
}
@property --tw-invert {
  syntax: "*";
  inherits: false;
}
@property --tw-opacity {
  syntax: "*";
  inherits: false;
}
@property --tw-saturate {
  syntax: "*";
  inherits: false;
}
@property --tw-sepia {
  syntax: "*";
  inherits: false;
}
@property --tw-drop-shadow {
  syntax: "*";
  inherits: false;
}
@property --tw-drop-shadow-color {
  syntax: "*";
  inherits: false;
}
@property --tw-drop-shadow-alpha {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 100%;
}
@property --tw-drop-shadow-size {
  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-translate-x: 0;
      --tw-translate-y: 0;
      --tw-translate-z: 0;
      --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-blur: initial;
      --tw-brightness: initial;
      --tw-contrast: initial;
      --tw-grayscale: initial;
      --tw-hue-rotate: initial;
      --tw-invert: initial;
      --tw-opacity: initial;
      --tw-saturate: initial;
      --tw-sepia: initial;
      --tw-drop-shadow: initial;
      --tw-drop-shadow-color: initial;
      --tw-drop-shadow-alpha: 100%;
      --tw-drop-shadow-size: initial;
      --tw-duration: initial;
    }
  }
}