{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "PillNav-JS-CSS",
	"title": "PillNav",
	"description": "Minimal pill nav with sliding active highlight + smooth easing.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "PillNav.css",
			"target": "@components/PillNav.css",
			"content": ".pill-nav-container {\n  position: absolute;\n  top: 1em;\n  z-index: 99;\n}\n\n@media (max-width: 768px) {\n  .pill-nav-container {\n    width: 100%;\n    left: 0;\n  }\n}\n\n.pill-nav {\n  --nav-h: 42px;\n  --logo: 36px;\n  --pill-pad-x: 18px;\n  --pill-gap: 3px;\n  width: max-content;\n  display: flex;\n  align-items: center;\n  box-sizing: border-box;\n}\n\n@media (max-width: 768px) {\n  .pill-nav {\n    width: 100%;\n    justify-content: space-between;\n    padding: 0 1rem;\n    background: transparent;\n  }\n}\n\n.pill-nav-items {\n  position: relative;\n  display: flex;\n  align-items: center;\n  height: var(--nav-h);\n  background: var(--base, #000);\n  border-radius: 9999px;\n}\n\n.pill-logo {\n  width: var(--nav-h);\n  height: var(--nav-h);\n  border-radius: 50%;\n  background: var(--base, #000);\n  padding: 8px;\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  overflow: hidden;\n}\n\n.pill-logo img {\n  width: 100%;\n  height: 100%;\n  object-fit: cover;\n  display: block;\n}\n\n.pill-list {\n  list-style: none;\n  display: flex;\n  align-items: stretch;\n  gap: var(--pill-gap);\n  margin: 0;\n  padding: 3px;\n  height: 100%;\n}\n\n.pill-list > li {\n  display: flex;\n  height: 100%;\n}\n\n.pill {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  height: 100%;\n  padding: 0 var(--pill-pad-x);\n  background: var(--pill-bg, #fff);\n  color: var(--pill-text, var(--base, #000));\n  text-decoration: none;\n  border-radius: 9999px;\n  box-sizing: border-box;\n  font-weight: 600;\n  font-size: 16px;\n  line-height: 0;\n  text-transform: uppercase;\n  letter-spacing: 0.2px;\n  white-space: nowrap;\n  cursor: pointer;\n  position: relative;\n  overflow: hidden;\n}\n\n.pill .hover-circle {\n  position: absolute;\n  left: 50%;\n  bottom: 0;\n  border-radius: 50%;\n  background: var(--base, #000);\n  z-index: 1;\n  display: block;\n  pointer-events: none;\n  will-change: transform;\n}\n\n.pill .label-stack {\n  position: relative;\n  display: inline-block;\n  line-height: 1;\n  z-index: 2;\n}\n\n.pill .pill-label {\n  position: relative;\n  z-index: 2;\n  display: inline-block;\n  line-height: 1;\n  will-change: transform;\n}\n\n.pill .pill-label-hover {\n  position: absolute;\n  left: 0;\n  top: 0;\n  color: var(--hover-text, #fff);\n  z-index: 3;\n  display: inline-block;\n  will-change: transform, opacity;\n}\n\n.pill.is-active::after {\n  content: '';\n  position: absolute;\n  bottom: -6px;\n  left: 50%;\n  transform: translateX(-50%);\n  width: 12px;\n  height: 12px;\n  background: var(--base, #000);\n  border-radius: 50px;\n  z-index: 4;\n}\n\n.desktop-only {\n  display: block;\n}\n\n.mobile-only {\n  display: none;\n}\n\n@media (max-width: 768px) {\n  .desktop-only {\n    display: none;\n  }\n\n  .mobile-only {\n    display: block;\n  }\n}\n\n.mobile-menu-button {\n  width: var(--nav-h);\n  height: var(--nav-h);\n  border-radius: 50%;\n  background: var(--base, #000);\n  border: none;\n  display: none;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  gap: 4px;\n  cursor: pointer;\n  padding: 0;\n  position: relative;\n}\n\n@media (max-width: 768px) {\n  .mobile-menu-button {\n    display: flex;\n  }\n}\n\n.hamburger-line {\n  width: 16px;\n  height: 2px;\n  background: var(--pill-bg, #fff);\n  border-radius: 1px;\n  transition: all 0.01s ease;\n  transform-origin: center;\n}\n\n.mobile-menu-popover {\n  position: absolute;\n  top: 3em;\n  left: 1rem;\n  right: 1rem;\n  background: var(--base, #f0f0f0);\n  border-radius: 27px;\n  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);\n  z-index: 998;\n  opacity: 0;\n  transform-origin: top center;\n  visibility: hidden;\n}\n\n.mobile-menu-list {\n  list-style: none;\n  margin: 0;\n  padding: 3px;\n  display: flex;\n  flex-direction: column;\n  gap: 3px;\n}\n\n.mobile-menu-popover .mobile-menu-link {\n  display: block;\n  padding: 12px 16px;\n  color: var(--pill-text, #fff);\n  background-color: var(--pill-bg, #fff);\n  text-decoration: none;\n  font-size: 16px;\n  font-weight: 500;\n  border-radius: 50px;\n  transition: all 0.2s ease;\n}\n\n.mobile-menu-popover .mobile-menu-link:hover {\n  cursor: pointer;\n  background-color: var(--base);\n  color: var(--hover-text, #fff);\n}\n"
		},
		{
			"type": "registry:component",
			"path": "PillNav.jsx",
			"content": "import { useEffect, useRef, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { gsap } from 'gsap';\nimport './PillNav.css';\n\nconst PillNav = ({\n  logo,\n  logoAlt = 'Logo',\n  items,\n  activeHref,\n  className = '',\n  ease = 'power3.easeOut',\n  baseColor = '#fff',\n  pillColor = '#120F17',\n  hoveredPillTextColor = '#120F17',\n  pillTextColor,\n  onMobileMenuClick,\n  initialLoadAnimation = true\n}) => {\n  const resolvedPillTextColor = pillTextColor ?? baseColor;\n  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);\n  const circleRefs = useRef([]);\n  const tlRefs = useRef([]);\n  const activeTweenRefs = useRef([]);\n  const logoImgRef = useRef(null);\n  const logoTweenRef = useRef(null);\n  const hamburgerRef = useRef(null);\n  const mobileMenuRef = useRef(null);\n  const navItemsRef = useRef(null);\n  const logoRef = useRef(null);\n\n  useEffect(() => {\n    const layout = () => {\n      circleRefs.current.forEach(circle => {\n        if (!circle?.parentElement) return;\n\n        const pill = circle.parentElement;\n        const rect = pill.getBoundingClientRect();\n        const { width: w, height: h } = rect;\n        const R = ((w * w) / 4 + h * h) / (2 * h);\n        const D = Math.ceil(2 * R) + 2;\n        const delta = Math.ceil(R - Math.sqrt(Math.max(0, R * R - (w * w) / 4))) + 1;\n        const originY = D - delta;\n\n        circle.style.width = `${D}px`;\n        circle.style.height = `${D}px`;\n        circle.style.bottom = `-${delta}px`;\n\n        gsap.set(circle, {\n          xPercent: -50,\n          scale: 0,\n          transformOrigin: `50% ${originY}px`\n        });\n\n        const label = pill.querySelector('.pill-label');\n        const white = pill.querySelector('.pill-label-hover');\n\n        if (label) gsap.set(label, { y: 0 });\n        if (white) gsap.set(white, { y: h + 12, opacity: 0 });\n\n        const index = circleRefs.current.indexOf(circle);\n        if (index === -1) return;\n\n        tlRefs.current[index]?.kill();\n        const tl = gsap.timeline({ paused: true });\n\n        tl.to(circle, { scale: 1.2, xPercent: -50, duration: 2, ease, overwrite: 'auto' }, 0);\n\n        if (label) {\n          tl.to(label, { y: -(h + 8), duration: 2, ease, overwrite: 'auto' }, 0);\n        }\n\n        if (white) {\n          gsap.set(white, { y: Math.ceil(h + 100), opacity: 0 });\n          tl.to(white, { y: 0, opacity: 1, duration: 2, ease, overwrite: 'auto' }, 0);\n        }\n\n        tlRefs.current[index] = tl;\n      });\n    };\n\n    layout();\n\n    const onResize = () => layout();\n    window.addEventListener('resize', onResize);\n\n    if (document.fonts?.ready) {\n      document.fonts.ready.then(layout).catch(() => {});\n    }\n\n    const menu = mobileMenuRef.current;\n    if (menu) {\n      gsap.set(menu, { visibility: 'hidden', opacity: 0, scaleY: 1 });\n    }\n\n    if (initialLoadAnimation) {\n      const logo = logoRef.current;\n      const navItems = navItemsRef.current;\n\n      if (logo) {\n        gsap.set(logo, { scale: 0 });\n        gsap.to(logo, {\n          scale: 1,\n          duration: 0.6,\n          ease\n        });\n      }\n\n      if (navItems) {\n        gsap.set(navItems, { width: 0, overflow: 'hidden' });\n        gsap.to(navItems, {\n          width: 'auto',\n          duration: 0.6,\n          ease\n        });\n      }\n    }\n\n    return () => window.removeEventListener('resize', onResize);\n  }, [items, ease, initialLoadAnimation]);\n\n  const handleEnter = i => {\n    const tl = tlRefs.current[i];\n    if (!tl) return;\n    activeTweenRefs.current[i]?.kill();\n    activeTweenRefs.current[i] = tl.tweenTo(tl.duration(), {\n      duration: 0.3,\n      ease,\n      overwrite: 'auto'\n    });\n  };\n\n  const handleLeave = i => {\n    const tl = tlRefs.current[i];\n    if (!tl) return;\n    activeTweenRefs.current[i]?.kill();\n    activeTweenRefs.current[i] = tl.tweenTo(0, {\n      duration: 0.2,\n      ease,\n      overwrite: 'auto'\n    });\n  };\n\n  const handleLogoEnter = () => {\n    const img = logoImgRef.current;\n    if (!img) return;\n    logoTweenRef.current?.kill();\n    gsap.set(img, { rotate: 0 });\n    logoTweenRef.current = gsap.to(img, {\n      rotate: 360,\n      duration: 0.2,\n      ease,\n      overwrite: 'auto'\n    });\n  };\n\n  const toggleMobileMenu = () => {\n    const newState = !isMobileMenuOpen;\n    setIsMobileMenuOpen(newState);\n\n    const hamburger = hamburgerRef.current;\n    const menu = mobileMenuRef.current;\n\n    if (hamburger) {\n      const lines = hamburger.querySelectorAll('.hamburger-line');\n      if (newState) {\n        gsap.to(lines[0], { rotation: 45, y: 3, duration: 0.3, ease });\n        gsap.to(lines[1], { rotation: -45, y: -3, duration: 0.3, ease });\n      } else {\n        gsap.to(lines[0], { rotation: 0, y: 0, duration: 0.3, ease });\n        gsap.to(lines[1], { rotation: 0, y: 0, duration: 0.3, ease });\n      }\n    }\n\n    if (menu) {\n      if (newState) {\n        gsap.set(menu, { visibility: 'visible' });\n        gsap.fromTo(\n          menu,\n          { opacity: 0, y: 10, scaleY: 1 },\n          {\n            opacity: 1,\n            y: 0,\n            scaleY: 1,\n            duration: 0.3,\n            ease,\n            transformOrigin: 'top center'\n          }\n        );\n      } else {\n        gsap.to(menu, {\n          opacity: 0,\n          y: 10,\n          scaleY: 1,\n          duration: 0.2,\n          ease,\n          transformOrigin: 'top center',\n          onComplete: () => {\n            gsap.set(menu, { visibility: 'hidden' });\n          }\n        });\n      }\n    }\n\n    onMobileMenuClick?.();\n  };\n\n  const isExternalLink = href =>\n    href.startsWith('http://') ||\n    href.startsWith('https://') ||\n    href.startsWith('//') ||\n    href.startsWith('mailto:') ||\n    href.startsWith('tel:') ||\n    href.startsWith('#');\n\n  const isRouterLink = href => href && !isExternalLink(href);\n\n  const cssVars = {\n    ['--base']: baseColor,\n    ['--pill-bg']: pillColor,\n    ['--hover-text']: hoveredPillTextColor,\n    ['--pill-text']: resolvedPillTextColor\n  };\n\n  return (\n    <div className=\"pill-nav-container\">\n      <nav className={`pill-nav ${className}`} aria-label=\"Primary\" style={cssVars}>\n        {isRouterLink(items?.[0]?.href) ? (\n          <Link\n            className=\"pill-logo\"\n            to={items[0].href}\n            aria-label=\"Home\"\n            onMouseEnter={handleLogoEnter}\n            role=\"menuitem\"\n            ref={el => {\n              logoRef.current = el;\n            }}\n          >\n            <img src={logo} alt={logoAlt} ref={logoImgRef} />\n          </Link>\n        ) : (\n          <a\n            className=\"pill-logo\"\n            href={items?.[0]?.href || '#'}\n            aria-label=\"Home\"\n            onMouseEnter={handleLogoEnter}\n            ref={el => {\n              logoRef.current = el;\n            }}\n          >\n            <img src={logo} alt={logoAlt} ref={logoImgRef} />\n          </a>\n        )}\n\n        <div className=\"pill-nav-items desktop-only\" ref={navItemsRef}>\n          <ul className=\"pill-list\" role=\"menubar\">\n            {items.map((item, i) => (\n              <li key={item.href || `item-${i}`} role=\"none\">\n                {isRouterLink(item.href) ? (\n                  <Link\n                    role=\"menuitem\"\n                    to={item.href}\n                    className={`pill${activeHref === item.href ? ' is-active' : ''}`}\n                    aria-label={item.ariaLabel || item.label}\n                    onMouseEnter={() => handleEnter(i)}\n                    onMouseLeave={() => handleLeave(i)}\n                  >\n                    <span\n                      className=\"hover-circle\"\n                      aria-hidden=\"true\"\n                      ref={el => {\n                        circleRefs.current[i] = el;\n                      }}\n                    />\n                    <span className=\"label-stack\">\n                      <span className=\"pill-label\">{item.label}</span>\n                      <span className=\"pill-label-hover\" aria-hidden=\"true\">\n                        {item.label}\n                      </span>\n                    </span>\n                  </Link>\n                ) : (\n                  <a\n                    role=\"menuitem\"\n                    href={item.href}\n                    className={`pill${activeHref === item.href ? ' is-active' : ''}`}\n                    aria-label={item.ariaLabel || item.label}\n                    onMouseEnter={() => handleEnter(i)}\n                    onMouseLeave={() => handleLeave(i)}\n                  >\n                    <span\n                      className=\"hover-circle\"\n                      aria-hidden=\"true\"\n                      ref={el => {\n                        circleRefs.current[i] = el;\n                      }}\n                    />\n                    <span className=\"label-stack\">\n                      <span className=\"pill-label\">{item.label}</span>\n                      <span className=\"pill-label-hover\" aria-hidden=\"true\">\n                        {item.label}\n                      </span>\n                    </span>\n                  </a>\n                )}\n              </li>\n            ))}\n          </ul>\n        </div>\n\n        <button\n          className=\"mobile-menu-button mobile-only\"\n          onClick={toggleMobileMenu}\n          aria-label=\"Toggle menu\"\n          ref={hamburgerRef}\n        >\n          <span className=\"hamburger-line\" />\n          <span className=\"hamburger-line\" />\n        </button>\n      </nav>\n\n      <div className=\"mobile-menu-popover mobile-only\" ref={mobileMenuRef} style={cssVars}>\n        <ul className=\"mobile-menu-list\">\n          {items.map((item, i) => (\n            <li key={item.href || `mobile-item-${i}`}>\n              {isRouterLink(item.href) ? (\n                <Link\n                  to={item.href}\n                  className={`mobile-menu-link${activeHref === item.href ? ' is-active' : ''}`}\n                  onClick={() => setIsMobileMenuOpen(false)}\n                >\n                  {item.label}\n                </Link>\n              ) : (\n                <a\n                  href={item.href}\n                  className={`mobile-menu-link${activeHref === item.href ? ' is-active' : ''}`}\n                  onClick={() => setIsMobileMenuOpen(false)}\n                >\n                  {item.label}\n                </a>\n              )}\n            </li>\n          ))}\n        </ul>\n      </div>\n    </div>\n  );\n};\n\nexport default PillNav;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"react-router-dom@^6.30.1",
		"gsap@^3.13.0"
	]
}