{
  "slug": "mac-switch",
  "name": "Mac Switch",
  "description": "Apple-inspired macOS liquid glass switch with refractive lip bezel optics, spring-loaded tactile thumb kinematics, and customizable color themes.",
  "summary": "A native-feeling macOS switch component built with physics-based liquid glass optics and harmonic oscillator springs. Features real-time squircle normal-map displacement with lip bezel curvature, specular edge reflections, dynamic transparency, and fluid track morphing between neutral zinc and vibrant Apple accent colors, coupled with responsive pointer capture dragging, multiple sizes, materials, and keyboard navigation.",
  "category": "sliders-and-toggles",
  "tags": [
    "switch",
    "toggle",
    "liquid-glass",
    "refraction",
    "macos",
    "physics",
    "spring",
    "apple"
  ],
  "dependencies": [
    "clsx",
    "tailwind-merge",
    "motion"
  ],
  "version": "1.0.0",
  "createdDate": "2026-09-24",
  "updatedDate": "2026-09-24",
  "interactive": true,
  "supportsColor": false,
  "highlights": [
    "Ultra-smooth pointer-capture tracking with zero-latency MotionValue synchronization and drag overflow damping",
    "Real-time squircle normal-map refraction distortion using SVG feDisplacementMap with lip bezel optics",
    "Dynamic specular lighting highlights along the 19px lip bezel lens contour",
    "Damped springs: thumb travel at stiffness 520 / damping 42, press expansion at stiffness 600 / damping 42",
    "Fluid track color morphing from neutral zinc to vibrant macOS system tints via motion mix interpolation",
    "Three size presets (sm, md, lg) and three glass optical materials (liquid, frosted, clear)",
    "Seven macOS color themes including Green, Blue, Purple, Orange, Pink, Amber, and Graphite",
    "Full keyboard accessibility with Space, Enter, ArrowLeft, ArrowRight, and ARIA switch semantics",
    "Optical props are synced into MotionValues without re-rendering"
  ],
  "anatomy": [
    "<motion.div> (Track shell with role=\"switch\", ARIA checked attributes, and focus ring)",
    "<SwitchFilter> (Scoped SVG filter with normal map, feGaussianBlur, feDisplacementMap, feSpecularLighting, feColorMatrix)",
    "<motion.div> (Draggable thumb pill with spring-driven scale, liquid background, and specular sheen)"
  ],
  "physics": {
    "engine": "Harmonic Damped Spring Oscillator & SVG Refraction Shader",
    "description": "Spring-driven thumb travel, press scale, backdrop opacity and track color, combined with an SVG displacement filter.",
    "parameters": [
      {
        "label": "Rest Scale",
        "value": "0.65 (95px × 60px)"
      },
      {
        "label": "Active Scale",
        "value": "0.90 (131px × 83px)"
      },
      {
        "label": "Scale Stiffness",
        "value": "600"
      },
      {
        "label": "Scale Damping",
        "value": "42"
      },
      {
        "label": "Travel Stiffness",
        "value": "520"
      },
      {
        "label": "Travel Damping",
        "value": "42"
      },
      {
        "label": "Bezel Width",
        "value": "14px - 24px lip squircle"
      }
    ]
  },
  "accessibility": {
    "role": "switch",
    "aria": "Standard role=\"switch\" with aria-checked and focus-visible ring.",
    "reducedMotion": "With prefers-reduced-motion, the thumb and track change state instantly instead of springing.",
    "keyboard": [
      {
        "key": "Space / Enter",
        "description": "Toggle switch on/off."
      },
      {
        "key": "ArrowLeft",
        "description": "Turn switch off."
      },
      {
        "key": "ArrowRight",
        "description": "Turn switch on."
      }
    ]
  },
  "guidelines": {
    "recommended": [
      "System preferences, feature toggles, and settings panels where authentic macOS tactile feel is desired",
      "Control Center style toggles and mode selectors",
      "Creative and luxury product interfaces showcasing liquid glass materials"
    ],
    "bestPractices": [
      "Position over visually rich backgrounds to showcase the optical refraction effect",
      "Ensure sufficient contrast between the off track color and the selected on color",
      "Pass checked and onChange for controlled state integration"
    ]
  },
  "props": [
    {
      "name": "checked",
      "type": "boolean",
      "defaultValue": "undefined",
      "description": "Controlled checked state of the switch."
    },
    {
      "name": "defaultChecked",
      "type": "boolean",
      "defaultValue": "false",
      "description": "Initial checked state when used uncontrolled."
    },
    {
      "name": "color",
      "type": "\"green\" | \"blue\" | \"purple\" | \"orange\" | \"pink\" | \"amber\" | \"monochrome\"",
      "defaultValue": "\"green\"",
      "description": "Vibrant macOS accent theme for the active track fill."
    },
    {
      "name": "size",
      "type": "\"sm\" | \"md\" | \"lg\"",
      "defaultValue": "\"md\"",
      "description": "Size preset controlling track and thumb dimensions."
    },
    {
      "name": "material",
      "type": "\"liquid\" | \"frosted\" | \"clear\"",
      "defaultValue": "\"liquid\"",
      "description": "Optic material variant (liquid SVG refraction, frosted glass, or clear)."
    },
    {
      "name": "forceActive",
      "type": "boolean",
      "defaultValue": "false",
      "description": "Forces the glass thumb into expanded tactile state."
    },
    {
      "name": "specularOpacity",
      "type": "number",
      "defaultValue": "0.5",
      "description": "Specular light highlight intensity (0 - 1)."
    },
    {
      "name": "specularSaturation",
      "type": "number",
      "defaultValue": "6",
      "description": "Refracted light color saturation boost (0 - 50)."
    },
    {
      "name": "refractionLevel",
      "type": "number",
      "defaultValue": "1.0",
      "description": "Refractive normal map displacement factor (0 - 1)."
    },
    {
      "name": "blurLevel",
      "type": "number",
      "defaultValue": "0.2",
      "description": "Gaussian blur standard deviation in pixels (0 - 40)."
    },
    {
      "name": "onChange",
      "type": "(checked: boolean) => void",
      "defaultValue": "undefined",
      "description": "Callback invoked when the switch is toggled."
    },
    {
      "name": "disabled",
      "type": "boolean",
      "defaultValue": "false",
      "description": "Disables interaction with the switch."
    },
    {
      "name": "label",
      "type": "string",
      "defaultValue": "\"Toggle switch\"",
      "description": "Accessible name announced by screen readers for the switch. Pass a name that describes the setting it toggles."
    },
    {
      "name": "className",
      "type": "string",
      "defaultValue": "undefined",
      "description": "Additional CSS class names for outer container."
    }
  ],
  "usage": "\"use client\";\n\nimport { useState } from \"react\";\nimport { MacSwitch } from \"@/components/ui/mac-switch\";\n\nexport function MacSwitchDemo() {\n  const [enabled, setEnabled] = useState(true);\n\n  return <MacSwitch checked={enabled} onChange={setEnabled} color=\"green\" label=\"Wi-Fi\" />;\n}",
  "files": [
    {
      "name": "mac-switch.tsx",
      "path": "registry/ui/mac-switch.tsx",
      "code": "\"use client\";\n\nimport React, { useEffect, useRef, useId, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useReducedMotion,\n  useSpring,\n  useTransform,\n  mix,\n  type MotionValue,\n} from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type MacSwitchColor =\n  | \"green\"\n  | \"blue\"\n  | \"purple\"\n  | \"orange\"\n  | \"pink\"\n  | \"amber\"\n  | \"monochrome\";\n\nexport type MacSwitchSize = \"sm\" | \"md\" | \"lg\";\nexport type MacSwitchMaterial = \"liquid\" | \"frosted\" | \"clear\";\n\nexport interface SwitchFilterProps {\n  id?: string;\n  blur?: MotionValue<number> | number;\n  scaleRatio?: MotionValue<number> | number;\n  specularOpacity?: MotionValue<number> | number;\n  specularSaturation?: MotionValue<number> | number;\n  width?: number;\n  height?: number;\n  radius?: number;\n  bezelWidth?: number;\n}\n\nconst SWITCH_COLORS: Record<\n  MacSwitchColor,\n  { fill: string; dot: string; label: string; glow: string }\n> = {\n  green: {\n    fill: \"#34C759\",\n    dot: \"bg-emerald-500\",\n    label: \"Green\",\n    glow: \"rgba(52, 199, 89, 0.4)\",\n  },\n  blue: {\n    fill: \"#007AFF\",\n    dot: \"bg-blue-500\",\n    label: \"Blue\",\n    glow: \"rgba(0, 122, 255, 0.4)\",\n  },\n  purple: {\n    fill: \"#AF52DE\",\n    dot: \"bg-purple-500\",\n    label: \"Purple\",\n    glow: \"rgba(175, 82, 222, 0.4)\",\n  },\n  orange: {\n    fill: \"#FF9500\",\n    dot: \"bg-orange-500\",\n    label: \"Orange\",\n    glow: \"rgba(255, 149, 0, 0.4)\",\n  },\n  pink: {\n    fill: \"#FF2D55\",\n    dot: \"bg-pink-500\",\n    label: \"Pink\",\n    glow: \"rgba(255, 45, 85, 0.4)\",\n  },\n  amber: {\n    fill: \"#FFCC00\",\n    dot: \"bg-amber-400\",\n    label: \"Amber\",\n    glow: \"rgba(255, 204, 0, 0.4)\",\n  },\n  monochrome: {\n    fill: \"#8E8E93\",\n    dot: \"bg-zinc-300\",\n    label: \"Graphite\",\n    glow: \"rgba(142, 142, 147, 0.3)\",\n  },\n};\n\nconst SWITCH_SIZES: Record<\n  MacSwitchSize,\n  {\n    sliderWidth: number;\n    sliderHeight: number;\n    thumbWidth: number;\n    thumbHeight: number;\n    bezelWidth: number;\n  }\n> = {\n  sm: {\n    sliderWidth: 120,\n    sliderHeight: 50,\n    thumbWidth: 110,\n    thumbHeight: 69,\n    bezelWidth: 14,\n  },\n  md: {\n    sliderWidth: 160,\n    sliderHeight: 67,\n    thumbWidth: 146,\n    thumbHeight: 92,\n    bezelWidth: 19,\n  },\n  lg: {\n    sliderWidth: 200,\n    sliderHeight: 84,\n    thumbWidth: 182,\n    thumbHeight: 115,\n    bezelWidth: 24,\n  },\n};\n\nfunction isMotionValue(val: unknown): val is MotionValue<number> {\n  return typeof val === \"object\" && val !== null && \"get\" in val && \"on\" in val;\n}\n\nfunction getNumericValue(\n  val?: MotionValue<number> | number,\n  fallback = 0,\n): number {\n  if (val === undefined) return fallback;\n  if (isMotionValue(val)) return Number(val.get()) || fallback;\n  return Number(val) || fallback;\n}\n\nexport const SwitchFilter: React.FC<SwitchFilterProps> = ({\n  id = \"thumb-filter-switch\",\n  blur,\n  scaleRatio,\n  specularOpacity,\n  specularSaturation,\n  width = 146,\n  height = 92,\n  radius = 46,\n  bezelWidth = 19,\n}) => {\n  const feImageRef = useRef<SVGFEImageElement>(null);\n  const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n  const dispRef = useRef<SVGFEDisplacementMapElement>(null);\n  const specRef = useRef<SVGFESpecularLightingElement>(null);\n  const satRef = useRef<SVGFEColorMatrixElement>(null);\n\n  useEffect(() => {\n    if (typeof document === \"undefined\") return;\n\n    const canvas = document.createElement(\"canvas\");\n    canvas.width = width;\n    canvas.height = height;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    const imgData = ctx.createImageData(width, height);\n    const data = imgData.data;\n    let pos = 0;\n\n    for (let y = 0; y < height; y++) {\n      for (let x = 0; x < width; x++) {\n        const segX = Math.max(radius, Math.min(width - radius, x));\n        const segY = height / 2;\n        const dx = x - segX;\n        const dy = y - segY;\n        const dist = Math.sqrt(dx * dx + dy * dy);\n        const distEdge = radius - dist;\n\n        if (distEdge <= 0 || distEdge >= bezelWidth) {\n          data[pos++] = 128;\n          data[pos++] = 128;\n          data[pos++] = 255;\n          data[pos++] = 255;\n        } else {\n          const u = distEdge / bezelWidth;\n          const slope = Math.sin(u * Math.PI) * (1 - 0.25 * u);\n          const dirX = dist > 0.001 ? dx / dist : 0;\n          const dirY = dist > 0.001 ? dy / dist : 0;\n          const nx = -dirX * slope * 0.9;\n          const ny = -dirY * slope * 0.9;\n          const nz = Math.sqrt(Math.max(0, 1 - nx * nx - ny * ny));\n\n          data[pos++] = Math.round(128 + 127 * nx);\n          data[pos++] = Math.round(128 + 127 * ny);\n          data[pos++] = Math.round(128 + 127 * nz);\n          data[pos++] = 255;\n        }\n      }\n    }\n\n    ctx.putImageData(imgData, 0, 0);\n    const dataUrl = canvas.toDataURL(\"image/png\");\n    feImageRef.current?.setAttribute(\"href\", dataUrl);\n  }, [width, height, radius, bezelWidth]);\n\n  useEffect(() => {\n    const unsubBlur = isMotionValue(blur)\n      ? blur.on(\"change\", (v) => {\n          blurRef.current?.setAttribute(\"stdDeviation\", String(v));\n        })\n      : undefined;\n\n    const unsubDisp = isMotionValue(scaleRatio)\n      ? scaleRatio.on(\"change\", (v) => {\n          dispRef.current?.setAttribute(\"scale\", String(v * 24));\n        })\n      : undefined;\n\n    const unsubSpec = isMotionValue(specularOpacity)\n      ? specularOpacity.on(\"change\", (v) => {\n          specRef.current?.setAttribute(\"specularConstant\", String(v * 1.5));\n        })\n      : undefined;\n\n    const unsubSat = isMotionValue(specularSaturation)\n      ? specularSaturation.on(\"change\", (v) => {\n          satRef.current?.setAttribute(\"values\", String(1 + v * 0.15));\n        })\n      : undefined;\n\n    const currentBlur = getNumericValue(blur, 0.2);\n    const currentScale = getNumericValue(scaleRatio, 0.4);\n    const currentSpec = getNumericValue(specularOpacity, 0.5);\n    const currentSat = getNumericValue(specularSaturation, 6);\n\n    blurRef.current?.setAttribute(\"stdDeviation\", String(currentBlur));\n    dispRef.current?.setAttribute(\"scale\", String(currentScale * 24));\n    specRef.current?.setAttribute(\n      \"specularConstant\",\n      String(currentSpec * 1.5),\n    );\n    satRef.current?.setAttribute(\"values\", String(1 + currentSat * 0.15));\n\n    return () => {\n      unsubBlur?.();\n      unsubDisp?.();\n      unsubSpec?.();\n      unsubSat?.();\n    };\n  }, [blur, scaleRatio, specularOpacity, specularSaturation]);\n\n  const initialBlur = getNumericValue(blur, 0.2);\n  const initialDisp = getNumericValue(scaleRatio, 0.4) * 24;\n  const initialSpec = getNumericValue(specularOpacity, 0.5) * 1.5;\n  const initialSat = 1 + getNumericValue(specularSaturation, 6) * 0.15;\n\n  return (\n    <svg\n      width=\"0\"\n      height=\"0\"\n      className=\"pointer-events-none absolute -z-10 opacity-0\"\n      aria-hidden=\"true\"\n    >\n      <defs>\n        <filter\n          id={id}\n          x=\"-20%\"\n          y=\"-20%\"\n          width=\"140%\"\n          height=\"140%\"\n          colorInterpolationFilters=\"sRGB\"\n        >\n          <feImage\n            ref={feImageRef}\n            result=\"normalMap\"\n            x=\"0\"\n            y=\"0\"\n            width={width}\n            height={height}\n            preserveAspectRatio=\"none\"\n          />\n          <feGaussianBlur\n            ref={blurRef}\n            in=\"SourceGraphic\"\n            stdDeviation={initialBlur}\n            result=\"blurred\"\n          />\n          <feDisplacementMap\n            ref={dispRef}\n            in=\"blurred\"\n            in2=\"normalMap\"\n            scale={initialDisp}\n            xChannelSelector=\"R\"\n            yChannelSelector=\"G\"\n            result=\"refracted\"\n          />\n          <feSpecularLighting\n            ref={specRef}\n            in=\"normalMap\"\n            surfaceScale=\"2\"\n            specularConstant={initialSpec}\n            specularExponent=\"24\"\n            result=\"specular\"\n            lightingColor=\"#ffffff\"\n          >\n            <feDistantLight azimuth=\"235\" elevation=\"55\" />\n          </feSpecularLighting>\n          <feColorMatrix\n            ref={satRef}\n            in=\"refracted\"\n            type=\"saturate\"\n            values={String(initialSat)}\n            result=\"saturated\"\n          />\n          <feBlend in=\"saturated\" in2=\"specular\" mode=\"screen\" />\n        </filter>\n      </defs>\n    </svg>\n  );\n};\n\nexport const Filter = SwitchFilter;\n\ntype SpringConfig = Parameters<typeof useSpring>[1];\n\nfunction useReducibleSpring(\n  source: MotionValue<number>,\n  config: SpringConfig,\n  instant: boolean,\n): MotionValue<number> {\n  const spring = useSpring(source, config);\n  return instant ? source : spring;\n}\n\nexport interface MacSwitchProps {\n  checked?: boolean;\n  defaultChecked?: boolean;\n  onChange?: (checked: boolean) => void;\n  disabled?: boolean;\n  size?: MacSwitchSize;\n  color?: MacSwitchColor;\n  material?: MacSwitchMaterial;\n  forceActive?: boolean;\n  specularOpacity?: number;\n  specularSaturation?: number;\n  refractionLevel?: number;\n  blurLevel?: number;\n  className?: string;\n  label?: string;\n}\n\nexport const MacSwitch: React.FC<MacSwitchProps> = ({\n  checked: controlledChecked,\n  defaultChecked = false,\n  onChange,\n  disabled = false,\n  size = \"md\",\n  color = \"green\",\n  material = \"liquid\",\n  forceActive = false,\n  specularOpacity: specularOpacityProp = 0.5,\n  specularSaturation: specularSaturationProp = 6,\n  refractionLevel = 1.0,\n  blurLevel = 0.2,\n  className,\n  label = \"Toggle switch\",\n}) => {\n  const generatedId = useId();\n  const reduceMotion = useReducedMotion() ?? false;\n  const filterId = `mac-switch-filter-${generatedId.replace(/:/g, \"\")}`;\n\n  const currentTheme = SWITCH_COLORS[color] ?? SWITCH_COLORS.green;\n  const currentSize = SWITCH_SIZES[size] ?? SWITCH_SIZES.md;\n  const { sliderWidth, sliderHeight, thumbWidth, thumbHeight, bezelWidth } =\n    currentSize;\n\n  const thumbRadius = thumbHeight / 2;\n  const THUMB_REST_SCALE = 0.65;\n  const THUMB_ACTIVE_SCALE = 0.9;\n  const THUMB_REST_OFFSET = ((1 - THUMB_REST_SCALE) * thumbWidth) / 2;\n  const TRAVEL =\n    sliderWidth - sliderHeight - (thumbWidth - thumbHeight) * THUMB_REST_SCALE;\n  const thumbMarginLeft =\n    -THUMB_REST_OFFSET + (sliderHeight - thumbHeight * THUMB_REST_SCALE) / 2;\n\n  const isControlled = controlledChecked !== undefined;\n  const [uncontrolledChecked, setUncontrolledChecked] =\n    useState(defaultChecked);\n  const isChecked = isControlled ? controlledChecked : uncontrolledChecked;\n\n  const checked = useMotionValue(isChecked ? 1 : 0);\n  const pointerDown = useMotionValue(0);\n  const forceActiveMotion = useMotionValue(forceActive ? 1 : 0);\n  const xDragRatio = useMotionValue(isChecked ? 1 : 0);\n  const initialPointerX = useMotionValue(0);\n\n  const isDraggingRef = useRef(false);\n\n  useEffect(() => {\n    forceActiveMotion.set(forceActive ? 1 : 0);\n  }, [forceActive, forceActiveMotion]);\n\n  useEffect(() => {\n    if (controlledChecked !== undefined) {\n      const nextVal = controlledChecked ? 1 : 0;\n      checked.set(nextVal);\n      xDragRatio.set(nextVal);\n    }\n  }, [controlledChecked, checked, xDragRatio]);\n\n  const active = useTransform((): number =>\n    forceActiveMotion.get() > 0.5 || pointerDown.get() > 0.5 ? 1 : 0,\n  );\n\n  const blur = useMotionValue(blurLevel);\n  const specularOpacity = useMotionValue(specularOpacityProp);\n  const specularSaturation = useMotionValue(specularSaturationProp);\n  const refractionBase = useMotionValue(refractionLevel);\n\n  useEffect(() => {\n    blur.set(blurLevel);\n  }, [blurLevel, blur]);\n\n  useEffect(() => {\n    specularOpacity.set(specularOpacityProp);\n  }, [specularOpacityProp, specularOpacity]);\n\n  useEffect(() => {\n    specularSaturation.set(specularSaturationProp);\n  }, [specularSaturationProp, specularSaturation]);\n\n  useEffect(() => {\n    refractionBase.set(refractionLevel);\n  }, [refractionLevel, refractionBase]);\n\n  const xRatio = useReducibleSpring(\n    useTransform((): number => {\n      const c = checked.get();\n      const dragRatio = xDragRatio.get();\n      if (pointerDown.get() > 0.5) {\n        return dragRatio;\n      }\n      return c > 0.5 ? 1 : 0;\n    }),\n    { damping: 42, stiffness: 520, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const backgroundOpacity = useReducibleSpring(\n    useTransform(active, (v) => 1 - 0.9 * v),\n    { damping: 42, stiffness: 600, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const thumbScale = useReducibleSpring(\n    useTransform(\n      active,\n      (v) => THUMB_REST_SCALE + (THUMB_ACTIVE_SCALE - THUMB_REST_SCALE) * v,\n    ),\n    { damping: 42, stiffness: 600, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const scaleRatio = useReducibleSpring(\n    useTransform(() => (0.4 + 0.5 * active.get()) * refractionBase.get()),\n    { damping: 42, stiffness: 600, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const considerChecked = useTransform((): number => {\n    const x = xDragRatio.get();\n    const c = checked.get();\n    return pointerDown.get() > 0.5 ? (x > 0.5 ? 1 : 0) : c > 0.5 ? 1 : 0;\n  });\n\n  const backgroundColor = useTransform(\n    useReducibleSpring(\n      considerChecked,\n      { damping: 42, stiffness: 520 },\n      reduceMotion,\n    ),\n    mix(\"#94949F55\", currentTheme.fill),\n  );\n\n  const thumbX = useTransform(xRatio, (r) => r * TRAVEL);\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (disabled) return;\n    isDraggingRef.current = true;\n    pointerDown.set(1);\n    initialPointerX.set(e.clientX);\n    xDragRatio.set(checked.get());\n    try {\n      e.currentTarget.setPointerCapture(e.pointerId);\n    } catch {}\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDraggingRef.current || disabled) return;\n    const baseRatio = checked.get();\n    const displacementX = e.clientX - initialPointerX.get();\n    const ratio = baseRatio + displacementX / TRAVEL;\n    const overflow = ratio < 0 ? -ratio : ratio > 1 ? ratio - 1 : 0;\n    const overflowSign = ratio < 0 ? -1 : 1;\n    const dampedOverflow = (overflowSign * overflow) / 22;\n    xDragRatio.set(Math.min(1, Math.max(0, ratio)) + dampedOverflow);\n  };\n\n  const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDraggingRef.current) return;\n    isDraggingRef.current = false;\n    pointerDown.set(0);\n\n    try {\n      e.currentTarget.releasePointerCapture(e.pointerId);\n    } catch {}\n\n    const displacement = Math.abs(e.clientX - initialPointerX.get());\n    let nextChecked: boolean;\n    if (displacement < 4) {\n      nextChecked = checked.get() < 0.5;\n    } else {\n      nextChecked = xDragRatio.get() > 0.5;\n    }\n\n    const nextVal = nextChecked ? 1 : 0;\n    checked.set(nextVal);\n    xDragRatio.set(nextVal);\n    if (!isControlled) {\n      setUncontrolledChecked(nextChecked);\n    }\n    onChange?.(nextChecked);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (disabled) return;\n    if (e.key === \" \" || e.key === \"Enter\") {\n      e.preventDefault();\n      const nextChecked = checked.get() < 0.5;\n      const nextVal = nextChecked ? 1 : 0;\n      checked.set(nextVal);\n      xDragRatio.set(nextVal);\n      if (!isControlled) {\n        setUncontrolledChecked(nextChecked);\n      }\n      onChange?.(nextChecked);\n    } else if (e.key === \"ArrowLeft\") {\n      e.preventDefault();\n      checked.set(0);\n      xDragRatio.set(0);\n      if (!isControlled) {\n        setUncontrolledChecked(false);\n      }\n      onChange?.(false);\n    } else if (e.key === \"ArrowRight\") {\n      e.preventDefault();\n      checked.set(1);\n      xDragRatio.set(1);\n      if (!isControlled) {\n        setUncontrolledChecked(true);\n      }\n      onChange?.(true);\n    }\n  };\n\n  const backdropStyle =\n    material === \"liquid\"\n      ? `url(#${filterId}) blur(14px)`\n      : material === \"frosted\"\n        ? \"blur(24px) saturate(180%)\"\n        : \"blur(8px) saturate(120%)\";\n\n  return (\n    <div\n      className={cn(\n        \"relative flex items-center justify-center select-none py-4\",\n        disabled && \"opacity-50 pointer-events-none\",\n        className,\n      )}\n    >\n      {material === \"liquid\" && (\n        <SwitchFilter\n          id={filterId}\n          blur={blur}\n          scaleRatio={scaleRatio}\n          specularOpacity={specularOpacity}\n          specularSaturation={specularSaturation}\n          width={thumbWidth}\n          height={thumbHeight}\n          radius={thumbRadius}\n          bezelWidth={bezelWidth}\n        />\n      )}\n\n      <motion.div\n        role=\"switch\"\n        aria-checked={isChecked}\n        aria-label={label}\n        aria-disabled={disabled || undefined}\n        tabIndex={disabled ? -1 : 0}\n        onKeyDown={handleKeyDown}\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={handlePointerUp}\n        onPointerCancel={handlePointerUp}\n        className=\"relative inline-block touch-none select-none cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50\"\n        style={{\n          width: sliderWidth,\n          height: sliderHeight,\n          backgroundColor: backgroundColor,\n          borderRadius: sliderHeight / 2,\n          boxShadow: \"inset 0 1px 3px rgba(0, 0, 0, 0.15)\",\n        }}\n      >\n        <motion.div\n          className=\"absolute pointer-events-none\"\n          style={{\n            height: thumbHeight,\n            width: thumbWidth,\n            marginLeft: thumbMarginLeft,\n            x: thumbX,\n            y: \"-50%\",\n            borderRadius: thumbRadius,\n            top: sliderHeight / 2,\n            backdropFilter: backdropStyle,\n            WebkitBackdropFilter: backdropStyle,\n            scale: thumbScale,\n            willChange: \"transform\",\n            backgroundColor: useTransform(\n              backgroundOpacity,\n              (op) => `rgba(255, 255, 255, ${op})`,\n            ),\n            boxShadow: useTransform(() => {\n              const isPressed = pointerDown.get() > 0.5;\n              return (\n                \"0 4px 22px rgba(0, 0, 0, 0.14), inset 0 1px 1.5px rgba(255, 255, 255, 0.85)\" +\n                (isPressed\n                  ? \", inset 2px 7px 24px rgba(0,0,0,0.09), inset -2px -7px 24px rgba(255,255,255,0.09)\"\n                  : \"\")\n              );\n            }),\n            border: \"0.5px solid rgba(255, 255, 255, 0.4)\",\n          }}\n        >\n          <div\n            className=\"pointer-events-none absolute inset-x-0 top-0 h-1/2 opacity-35\"\n            style={{\n              borderRadius: `${thumbRadius}px ${thumbRadius}px 0 0`,\n              background:\n                \"linear-gradient(180deg, rgba(255,255,255,0.65) 0%, rgba(255,255,255,0.05) 100%)\",\n            }}\n          />\n        </motion.div>\n      </motion.div>\n    </div>\n  );\n};\n\nexport const Switch = MacSwitch;\n",
      "content": "\"use client\";\n\nimport React, { useEffect, useRef, useId, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useReducedMotion,\n  useSpring,\n  useTransform,\n  mix,\n  type MotionValue,\n} from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type MacSwitchColor =\n  | \"green\"\n  | \"blue\"\n  | \"purple\"\n  | \"orange\"\n  | \"pink\"\n  | \"amber\"\n  | \"monochrome\";\n\nexport type MacSwitchSize = \"sm\" | \"md\" | \"lg\";\nexport type MacSwitchMaterial = \"liquid\" | \"frosted\" | \"clear\";\n\nexport interface SwitchFilterProps {\n  id?: string;\n  blur?: MotionValue<number> | number;\n  scaleRatio?: MotionValue<number> | number;\n  specularOpacity?: MotionValue<number> | number;\n  specularSaturation?: MotionValue<number> | number;\n  width?: number;\n  height?: number;\n  radius?: number;\n  bezelWidth?: number;\n}\n\nconst SWITCH_COLORS: Record<\n  MacSwitchColor,\n  { fill: string; dot: string; label: string; glow: string }\n> = {\n  green: {\n    fill: \"#34C759\",\n    dot: \"bg-emerald-500\",\n    label: \"Green\",\n    glow: \"rgba(52, 199, 89, 0.4)\",\n  },\n  blue: {\n    fill: \"#007AFF\",\n    dot: \"bg-blue-500\",\n    label: \"Blue\",\n    glow: \"rgba(0, 122, 255, 0.4)\",\n  },\n  purple: {\n    fill: \"#AF52DE\",\n    dot: \"bg-purple-500\",\n    label: \"Purple\",\n    glow: \"rgba(175, 82, 222, 0.4)\",\n  },\n  orange: {\n    fill: \"#FF9500\",\n    dot: \"bg-orange-500\",\n    label: \"Orange\",\n    glow: \"rgba(255, 149, 0, 0.4)\",\n  },\n  pink: {\n    fill: \"#FF2D55\",\n    dot: \"bg-pink-500\",\n    label: \"Pink\",\n    glow: \"rgba(255, 45, 85, 0.4)\",\n  },\n  amber: {\n    fill: \"#FFCC00\",\n    dot: \"bg-amber-400\",\n    label: \"Amber\",\n    glow: \"rgba(255, 204, 0, 0.4)\",\n  },\n  monochrome: {\n    fill: \"#8E8E93\",\n    dot: \"bg-zinc-300\",\n    label: \"Graphite\",\n    glow: \"rgba(142, 142, 147, 0.3)\",\n  },\n};\n\nconst SWITCH_SIZES: Record<\n  MacSwitchSize,\n  {\n    sliderWidth: number;\n    sliderHeight: number;\n    thumbWidth: number;\n    thumbHeight: number;\n    bezelWidth: number;\n  }\n> = {\n  sm: {\n    sliderWidth: 120,\n    sliderHeight: 50,\n    thumbWidth: 110,\n    thumbHeight: 69,\n    bezelWidth: 14,\n  },\n  md: {\n    sliderWidth: 160,\n    sliderHeight: 67,\n    thumbWidth: 146,\n    thumbHeight: 92,\n    bezelWidth: 19,\n  },\n  lg: {\n    sliderWidth: 200,\n    sliderHeight: 84,\n    thumbWidth: 182,\n    thumbHeight: 115,\n    bezelWidth: 24,\n  },\n};\n\nfunction isMotionValue(val: unknown): val is MotionValue<number> {\n  return typeof val === \"object\" && val !== null && \"get\" in val && \"on\" in val;\n}\n\nfunction getNumericValue(\n  val?: MotionValue<number> | number,\n  fallback = 0,\n): number {\n  if (val === undefined) return fallback;\n  if (isMotionValue(val)) return Number(val.get()) || fallback;\n  return Number(val) || fallback;\n}\n\nexport const SwitchFilter: React.FC<SwitchFilterProps> = ({\n  id = \"thumb-filter-switch\",\n  blur,\n  scaleRatio,\n  specularOpacity,\n  specularSaturation,\n  width = 146,\n  height = 92,\n  radius = 46,\n  bezelWidth = 19,\n}) => {\n  const feImageRef = useRef<SVGFEImageElement>(null);\n  const blurRef = useRef<SVGFEGaussianBlurElement>(null);\n  const dispRef = useRef<SVGFEDisplacementMapElement>(null);\n  const specRef = useRef<SVGFESpecularLightingElement>(null);\n  const satRef = useRef<SVGFEColorMatrixElement>(null);\n\n  useEffect(() => {\n    if (typeof document === \"undefined\") return;\n\n    const canvas = document.createElement(\"canvas\");\n    canvas.width = width;\n    canvas.height = height;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    const imgData = ctx.createImageData(width, height);\n    const data = imgData.data;\n    let pos = 0;\n\n    for (let y = 0; y < height; y++) {\n      for (let x = 0; x < width; x++) {\n        const segX = Math.max(radius, Math.min(width - radius, x));\n        const segY = height / 2;\n        const dx = x - segX;\n        const dy = y - segY;\n        const dist = Math.sqrt(dx * dx + dy * dy);\n        const distEdge = radius - dist;\n\n        if (distEdge <= 0 || distEdge >= bezelWidth) {\n          data[pos++] = 128;\n          data[pos++] = 128;\n          data[pos++] = 255;\n          data[pos++] = 255;\n        } else {\n          const u = distEdge / bezelWidth;\n          const slope = Math.sin(u * Math.PI) * (1 - 0.25 * u);\n          const dirX = dist > 0.001 ? dx / dist : 0;\n          const dirY = dist > 0.001 ? dy / dist : 0;\n          const nx = -dirX * slope * 0.9;\n          const ny = -dirY * slope * 0.9;\n          const nz = Math.sqrt(Math.max(0, 1 - nx * nx - ny * ny));\n\n          data[pos++] = Math.round(128 + 127 * nx);\n          data[pos++] = Math.round(128 + 127 * ny);\n          data[pos++] = Math.round(128 + 127 * nz);\n          data[pos++] = 255;\n        }\n      }\n    }\n\n    ctx.putImageData(imgData, 0, 0);\n    const dataUrl = canvas.toDataURL(\"image/png\");\n    feImageRef.current?.setAttribute(\"href\", dataUrl);\n  }, [width, height, radius, bezelWidth]);\n\n  useEffect(() => {\n    const unsubBlur = isMotionValue(blur)\n      ? blur.on(\"change\", (v) => {\n          blurRef.current?.setAttribute(\"stdDeviation\", String(v));\n        })\n      : undefined;\n\n    const unsubDisp = isMotionValue(scaleRatio)\n      ? scaleRatio.on(\"change\", (v) => {\n          dispRef.current?.setAttribute(\"scale\", String(v * 24));\n        })\n      : undefined;\n\n    const unsubSpec = isMotionValue(specularOpacity)\n      ? specularOpacity.on(\"change\", (v) => {\n          specRef.current?.setAttribute(\"specularConstant\", String(v * 1.5));\n        })\n      : undefined;\n\n    const unsubSat = isMotionValue(specularSaturation)\n      ? specularSaturation.on(\"change\", (v) => {\n          satRef.current?.setAttribute(\"values\", String(1 + v * 0.15));\n        })\n      : undefined;\n\n    const currentBlur = getNumericValue(blur, 0.2);\n    const currentScale = getNumericValue(scaleRatio, 0.4);\n    const currentSpec = getNumericValue(specularOpacity, 0.5);\n    const currentSat = getNumericValue(specularSaturation, 6);\n\n    blurRef.current?.setAttribute(\"stdDeviation\", String(currentBlur));\n    dispRef.current?.setAttribute(\"scale\", String(currentScale * 24));\n    specRef.current?.setAttribute(\n      \"specularConstant\",\n      String(currentSpec * 1.5),\n    );\n    satRef.current?.setAttribute(\"values\", String(1 + currentSat * 0.15));\n\n    return () => {\n      unsubBlur?.();\n      unsubDisp?.();\n      unsubSpec?.();\n      unsubSat?.();\n    };\n  }, [blur, scaleRatio, specularOpacity, specularSaturation]);\n\n  const initialBlur = getNumericValue(blur, 0.2);\n  const initialDisp = getNumericValue(scaleRatio, 0.4) * 24;\n  const initialSpec = getNumericValue(specularOpacity, 0.5) * 1.5;\n  const initialSat = 1 + getNumericValue(specularSaturation, 6) * 0.15;\n\n  return (\n    <svg\n      width=\"0\"\n      height=\"0\"\n      className=\"pointer-events-none absolute -z-10 opacity-0\"\n      aria-hidden=\"true\"\n    >\n      <defs>\n        <filter\n          id={id}\n          x=\"-20%\"\n          y=\"-20%\"\n          width=\"140%\"\n          height=\"140%\"\n          colorInterpolationFilters=\"sRGB\"\n        >\n          <feImage\n            ref={feImageRef}\n            result=\"normalMap\"\n            x=\"0\"\n            y=\"0\"\n            width={width}\n            height={height}\n            preserveAspectRatio=\"none\"\n          />\n          <feGaussianBlur\n            ref={blurRef}\n            in=\"SourceGraphic\"\n            stdDeviation={initialBlur}\n            result=\"blurred\"\n          />\n          <feDisplacementMap\n            ref={dispRef}\n            in=\"blurred\"\n            in2=\"normalMap\"\n            scale={initialDisp}\n            xChannelSelector=\"R\"\n            yChannelSelector=\"G\"\n            result=\"refracted\"\n          />\n          <feSpecularLighting\n            ref={specRef}\n            in=\"normalMap\"\n            surfaceScale=\"2\"\n            specularConstant={initialSpec}\n            specularExponent=\"24\"\n            result=\"specular\"\n            lightingColor=\"#ffffff\"\n          >\n            <feDistantLight azimuth=\"235\" elevation=\"55\" />\n          </feSpecularLighting>\n          <feColorMatrix\n            ref={satRef}\n            in=\"refracted\"\n            type=\"saturate\"\n            values={String(initialSat)}\n            result=\"saturated\"\n          />\n          <feBlend in=\"saturated\" in2=\"specular\" mode=\"screen\" />\n        </filter>\n      </defs>\n    </svg>\n  );\n};\n\nexport const Filter = SwitchFilter;\n\ntype SpringConfig = Parameters<typeof useSpring>[1];\n\nfunction useReducibleSpring(\n  source: MotionValue<number>,\n  config: SpringConfig,\n  instant: boolean,\n): MotionValue<number> {\n  const spring = useSpring(source, config);\n  return instant ? source : spring;\n}\n\nexport interface MacSwitchProps {\n  checked?: boolean;\n  defaultChecked?: boolean;\n  onChange?: (checked: boolean) => void;\n  disabled?: boolean;\n  size?: MacSwitchSize;\n  color?: MacSwitchColor;\n  material?: MacSwitchMaterial;\n  forceActive?: boolean;\n  specularOpacity?: number;\n  specularSaturation?: number;\n  refractionLevel?: number;\n  blurLevel?: number;\n  className?: string;\n  label?: string;\n}\n\nexport const MacSwitch: React.FC<MacSwitchProps> = ({\n  checked: controlledChecked,\n  defaultChecked = false,\n  onChange,\n  disabled = false,\n  size = \"md\",\n  color = \"green\",\n  material = \"liquid\",\n  forceActive = false,\n  specularOpacity: specularOpacityProp = 0.5,\n  specularSaturation: specularSaturationProp = 6,\n  refractionLevel = 1.0,\n  blurLevel = 0.2,\n  className,\n  label = \"Toggle switch\",\n}) => {\n  const generatedId = useId();\n  const reduceMotion = useReducedMotion() ?? false;\n  const filterId = `mac-switch-filter-${generatedId.replace(/:/g, \"\")}`;\n\n  const currentTheme = SWITCH_COLORS[color] ?? SWITCH_COLORS.green;\n  const currentSize = SWITCH_SIZES[size] ?? SWITCH_SIZES.md;\n  const { sliderWidth, sliderHeight, thumbWidth, thumbHeight, bezelWidth } =\n    currentSize;\n\n  const thumbRadius = thumbHeight / 2;\n  const THUMB_REST_SCALE = 0.65;\n  const THUMB_ACTIVE_SCALE = 0.9;\n  const THUMB_REST_OFFSET = ((1 - THUMB_REST_SCALE) * thumbWidth) / 2;\n  const TRAVEL =\n    sliderWidth - sliderHeight - (thumbWidth - thumbHeight) * THUMB_REST_SCALE;\n  const thumbMarginLeft =\n    -THUMB_REST_OFFSET + (sliderHeight - thumbHeight * THUMB_REST_SCALE) / 2;\n\n  const isControlled = controlledChecked !== undefined;\n  const [uncontrolledChecked, setUncontrolledChecked] =\n    useState(defaultChecked);\n  const isChecked = isControlled ? controlledChecked : uncontrolledChecked;\n\n  const checked = useMotionValue(isChecked ? 1 : 0);\n  const pointerDown = useMotionValue(0);\n  const forceActiveMotion = useMotionValue(forceActive ? 1 : 0);\n  const xDragRatio = useMotionValue(isChecked ? 1 : 0);\n  const initialPointerX = useMotionValue(0);\n\n  const isDraggingRef = useRef(false);\n\n  useEffect(() => {\n    forceActiveMotion.set(forceActive ? 1 : 0);\n  }, [forceActive, forceActiveMotion]);\n\n  useEffect(() => {\n    if (controlledChecked !== undefined) {\n      const nextVal = controlledChecked ? 1 : 0;\n      checked.set(nextVal);\n      xDragRatio.set(nextVal);\n    }\n  }, [controlledChecked, checked, xDragRatio]);\n\n  const active = useTransform((): number =>\n    forceActiveMotion.get() > 0.5 || pointerDown.get() > 0.5 ? 1 : 0,\n  );\n\n  const blur = useMotionValue(blurLevel);\n  const specularOpacity = useMotionValue(specularOpacityProp);\n  const specularSaturation = useMotionValue(specularSaturationProp);\n  const refractionBase = useMotionValue(refractionLevel);\n\n  useEffect(() => {\n    blur.set(blurLevel);\n  }, [blurLevel, blur]);\n\n  useEffect(() => {\n    specularOpacity.set(specularOpacityProp);\n  }, [specularOpacityProp, specularOpacity]);\n\n  useEffect(() => {\n    specularSaturation.set(specularSaturationProp);\n  }, [specularSaturationProp, specularSaturation]);\n\n  useEffect(() => {\n    refractionBase.set(refractionLevel);\n  }, [refractionLevel, refractionBase]);\n\n  const xRatio = useReducibleSpring(\n    useTransform((): number => {\n      const c = checked.get();\n      const dragRatio = xDragRatio.get();\n      if (pointerDown.get() > 0.5) {\n        return dragRatio;\n      }\n      return c > 0.5 ? 1 : 0;\n    }),\n    { damping: 42, stiffness: 520, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const backgroundOpacity = useReducibleSpring(\n    useTransform(active, (v) => 1 - 0.9 * v),\n    { damping: 42, stiffness: 600, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const thumbScale = useReducibleSpring(\n    useTransform(\n      active,\n      (v) => THUMB_REST_SCALE + (THUMB_ACTIVE_SCALE - THUMB_REST_SCALE) * v,\n    ),\n    { damping: 42, stiffness: 600, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const scaleRatio = useReducibleSpring(\n    useTransform(() => (0.4 + 0.5 * active.get()) * refractionBase.get()),\n    { damping: 42, stiffness: 600, mass: 0.8 },\n    reduceMotion,\n  );\n\n  const considerChecked = useTransform((): number => {\n    const x = xDragRatio.get();\n    const c = checked.get();\n    return pointerDown.get() > 0.5 ? (x > 0.5 ? 1 : 0) : c > 0.5 ? 1 : 0;\n  });\n\n  const backgroundColor = useTransform(\n    useReducibleSpring(\n      considerChecked,\n      { damping: 42, stiffness: 520 },\n      reduceMotion,\n    ),\n    mix(\"#94949F55\", currentTheme.fill),\n  );\n\n  const thumbX = useTransform(xRatio, (r) => r * TRAVEL);\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (disabled) return;\n    isDraggingRef.current = true;\n    pointerDown.set(1);\n    initialPointerX.set(e.clientX);\n    xDragRatio.set(checked.get());\n    try {\n      e.currentTarget.setPointerCapture(e.pointerId);\n    } catch {}\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDraggingRef.current || disabled) return;\n    const baseRatio = checked.get();\n    const displacementX = e.clientX - initialPointerX.get();\n    const ratio = baseRatio + displacementX / TRAVEL;\n    const overflow = ratio < 0 ? -ratio : ratio > 1 ? ratio - 1 : 0;\n    const overflowSign = ratio < 0 ? -1 : 1;\n    const dampedOverflow = (overflowSign * overflow) / 22;\n    xDragRatio.set(Math.min(1, Math.max(0, ratio)) + dampedOverflow);\n  };\n\n  const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDraggingRef.current) return;\n    isDraggingRef.current = false;\n    pointerDown.set(0);\n\n    try {\n      e.currentTarget.releasePointerCapture(e.pointerId);\n    } catch {}\n\n    const displacement = Math.abs(e.clientX - initialPointerX.get());\n    let nextChecked: boolean;\n    if (displacement < 4) {\n      nextChecked = checked.get() < 0.5;\n    } else {\n      nextChecked = xDragRatio.get() > 0.5;\n    }\n\n    const nextVal = nextChecked ? 1 : 0;\n    checked.set(nextVal);\n    xDragRatio.set(nextVal);\n    if (!isControlled) {\n      setUncontrolledChecked(nextChecked);\n    }\n    onChange?.(nextChecked);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (disabled) return;\n    if (e.key === \" \" || e.key === \"Enter\") {\n      e.preventDefault();\n      const nextChecked = checked.get() < 0.5;\n      const nextVal = nextChecked ? 1 : 0;\n      checked.set(nextVal);\n      xDragRatio.set(nextVal);\n      if (!isControlled) {\n        setUncontrolledChecked(nextChecked);\n      }\n      onChange?.(nextChecked);\n    } else if (e.key === \"ArrowLeft\") {\n      e.preventDefault();\n      checked.set(0);\n      xDragRatio.set(0);\n      if (!isControlled) {\n        setUncontrolledChecked(false);\n      }\n      onChange?.(false);\n    } else if (e.key === \"ArrowRight\") {\n      e.preventDefault();\n      checked.set(1);\n      xDragRatio.set(1);\n      if (!isControlled) {\n        setUncontrolledChecked(true);\n      }\n      onChange?.(true);\n    }\n  };\n\n  const backdropStyle =\n    material === \"liquid\"\n      ? `url(#${filterId}) blur(14px)`\n      : material === \"frosted\"\n        ? \"blur(24px) saturate(180%)\"\n        : \"blur(8px) saturate(120%)\";\n\n  return (\n    <div\n      className={cn(\n        \"relative flex items-center justify-center select-none py-4\",\n        disabled && \"opacity-50 pointer-events-none\",\n        className,\n      )}\n    >\n      {material === \"liquid\" && (\n        <SwitchFilter\n          id={filterId}\n          blur={blur}\n          scaleRatio={scaleRatio}\n          specularOpacity={specularOpacity}\n          specularSaturation={specularSaturation}\n          width={thumbWidth}\n          height={thumbHeight}\n          radius={thumbRadius}\n          bezelWidth={bezelWidth}\n        />\n      )}\n\n      <motion.div\n        role=\"switch\"\n        aria-checked={isChecked}\n        aria-label={label}\n        aria-disabled={disabled || undefined}\n        tabIndex={disabled ? -1 : 0}\n        onKeyDown={handleKeyDown}\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={handlePointerUp}\n        onPointerCancel={handlePointerUp}\n        className=\"relative inline-block touch-none select-none cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50\"\n        style={{\n          width: sliderWidth,\n          height: sliderHeight,\n          backgroundColor: backgroundColor,\n          borderRadius: sliderHeight / 2,\n          boxShadow: \"inset 0 1px 3px rgba(0, 0, 0, 0.15)\",\n        }}\n      >\n        <motion.div\n          className=\"absolute pointer-events-none\"\n          style={{\n            height: thumbHeight,\n            width: thumbWidth,\n            marginLeft: thumbMarginLeft,\n            x: thumbX,\n            y: \"-50%\",\n            borderRadius: thumbRadius,\n            top: sliderHeight / 2,\n            backdropFilter: backdropStyle,\n            WebkitBackdropFilter: backdropStyle,\n            scale: thumbScale,\n            willChange: \"transform\",\n            backgroundColor: useTransform(\n              backgroundOpacity,\n              (op) => `rgba(255, 255, 255, ${op})`,\n            ),\n            boxShadow: useTransform(() => {\n              const isPressed = pointerDown.get() > 0.5;\n              return (\n                \"0 4px 22px rgba(0, 0, 0, 0.14), inset 0 1px 1.5px rgba(255, 255, 255, 0.85)\" +\n                (isPressed\n                  ? \", inset 2px 7px 24px rgba(0,0,0,0.09), inset -2px -7px 24px rgba(255,255,255,0.09)\"\n                  : \"\")\n              );\n            }),\n            border: \"0.5px solid rgba(255, 255, 255, 0.4)\",\n          }}\n        >\n          <div\n            className=\"pointer-events-none absolute inset-x-0 top-0 h-1/2 opacity-35\"\n            style={{\n              borderRadius: `${thumbRadius}px ${thumbRadius}px 0 0`,\n              background:\n                \"linear-gradient(180deg, rgba(255,255,255,0.65) 0%, rgba(255,255,255,0.05) 100%)\",\n            }}\n          />\n        </motion.div>\n      </motion.div>\n    </div>\n  );\n};\n\nexport const Switch = MacSwitch;\n",
      "type": "registry:ui",
      "target": "@ui/mac-switch.tsx"
    }
  ],
  "type": "registry:ui",
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "title": "Mac Switch"
}
