{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "CardNav-TS-CSS",
	"title": "CardNav",
	"description": "Expandable navigation bar with card panels revealing nested links.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "CardNav.css",
			"target": "@components/CardNav.css",
			"content": ".card-nav-container {\n  position: absolute;\n  top: 2em;\n  left: 50%;\n  transform: translateX(-50%);\n  width: 90%;\n  max-width: 800px;\n  z-index: 99;\n  box-sizing: border-box;\n}\n\n.card-nav {\n  display: block;\n  height: 60px;\n  padding: 0;\n  background-color: white;\n  border: 0.5px solid rgba(255, 255, 255, 0.1);\n  border-radius: 0.75rem;\n  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n  position: relative;\n  overflow: hidden;\n  will-change: height;\n}\n\n.card-nav-top {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 60px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  padding: 0.5rem 0.45rem 0.55rem 1.1rem;\n  z-index: 2;\n}\n\n.hamburger-menu {\n  height: 100%;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  cursor: pointer;\n  gap: 6px;\n}\n\n.hamburger-menu:hover .hamburger-line {\n  opacity: 0.75;\n}\n\n.hamburger-line {\n  width: 30px;\n  height: 2px;\n  background-color: currentColor;\n  transition:\n    transform 0.25s ease,\n    opacity 0.2s ease,\n    margin 0.3s ease;\n  transform-origin: 50% 50%;\n}\n\n.hamburger-menu.open .hamburger-line:first-child {\n  transform: translateY(4px) rotate(45deg);\n}\n\n.hamburger-menu.open .hamburger-line:last-child {\n  transform: translateY(-4px) rotate(-45deg);\n}\n\n.logo-container {\n  display: flex;\n  align-items: center;\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n}\n\n.logo {\n  height: 28px;\n}\n\n.card-nav-cta-button {\n  background-color: #111;\n  color: white;\n  border: none;\n  border-radius: calc(0.75rem - 0.35rem);\n  padding: 0 1rem;\n  height: 100%;\n  font-weight: 500;\n  cursor: pointer;\n  transition: background-color 0.3s ease;\n  align-items: center;\n}\n\n.card-nav-cta-button:hover {\n  background-color: #333;\n}\n\n.card-nav-content {\n  position: absolute;\n  left: 0;\n  right: 0;\n  top: 60px;\n  bottom: 0;\n  padding: 0.5rem;\n  display: flex;\n  align-items: flex-end;\n  gap: 12px;\n  visibility: hidden;\n  pointer-events: none;\n  z-index: 1;\n}\n\n.card-nav.open .card-nav-content {\n  visibility: visible;\n  pointer-events: auto;\n}\n\n.nav-card {\n  height: 100%;\n  flex: 1 1 0;\n  min-width: 0;\n  border-radius: calc(0.75rem - 0.2rem);\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  padding: 12px 16px;\n  gap: 8px;\n  user-select: none;\n}\n\n.nav-card-label {\n  font-weight: 400;\n  font-size: 22px;\n  letter-spacing: -0.5px;\n}\n\n.nav-card-links {\n  margin-top: auto;\n  display: flex;\n  flex-direction: column;\n  gap: 2px;\n}\n\n.nav-card-link {\n  font-size: 16px;\n  cursor: pointer;\n  text-decoration: none;\n  transition: opacity 0.3s ease;\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n}\n\n.nav-card-link:hover {\n  opacity: 0.75;\n}\n\n@media (max-width: 768px) {\n  .card-nav-container {\n    width: 90%;\n    top: 1.2em;\n  }\n\n  .card-nav-top {\n    padding: 0.5rem 1rem;\n    justify-content: space-between;\n  }\n\n  .hamburger-menu {\n    order: 2;\n  }\n\n  .logo-container {\n    position: static;\n    transform: none;\n    order: 1;\n  }\n\n  .card-nav-cta-button {\n    display: none;\n  }\n\n  .card-nav-content {\n    flex-direction: column;\n    align-items: stretch;\n    gap: 8px;\n    padding: 0.5rem;\n    bottom: 0;\n    justify-content: flex-start;\n  }\n\n  .nav-card {\n    height: auto;\n    min-height: 60px;\n    flex: 1 1 auto;\n    max-height: none;\n  }\n\n  .nav-card-label {\n    font-size: 18px;\n  }\n\n  .nav-card-link {\n    font-size: 15px;\n  }\n}\n"
		},
		{
			"type": "registry:component",
			"path": "CardNav.tsx",
			"content": "import React, { useLayoutEffect, useRef, useState } from 'react';\nimport { gsap } from 'gsap';\n// use your own icon import if react-icons is not available\nimport { GoArrowUpRight } from 'react-icons/go';\nimport './CardNav.css';\n\ntype CardNavLink = {\n  label: string;\n  href: string;\n  ariaLabel: string;\n};\n\nexport type CardNavItem = {\n  label: string;\n  bgColor: string;\n  textColor: string;\n  links: CardNavLink[];\n};\n\nexport interface CardNavProps {\n  logo: string;\n  logoAlt?: string;\n  items: CardNavItem[];\n  className?: string;\n  ease?: string;\n  baseColor?: string;\n  menuColor?: string;\n  buttonBgColor?: string;\n  buttonTextColor?: string;\n}\n\nconst CardNav: React.FC<CardNavProps> = ({\n  logo,\n  logoAlt = 'Logo',\n  items,\n  className = '',\n  ease = 'power3.out',\n  baseColor = '#fff',\n  menuColor,\n  buttonBgColor,\n  buttonTextColor\n}) => {\n  const [isHamburgerOpen, setIsHamburgerOpen] = useState(false);\n  const [isExpanded, setIsExpanded] = useState(false);\n  const navRef = useRef<HTMLDivElement | null>(null);\n  const cardsRef = useRef<HTMLDivElement[]>([]);\n  const tlRef = useRef<gsap.core.Timeline | null>(null);\n\n  const calculateHeight = () => {\n    const navEl = navRef.current;\n    if (!navEl) return 260;\n\n    const isMobile = window.matchMedia('(max-width: 768px)').matches;\n    if (isMobile) {\n      const contentEl = navEl.querySelector('.card-nav-content') as HTMLElement;\n      if (contentEl) {\n        const wasVisible = contentEl.style.visibility;\n        const wasPointerEvents = contentEl.style.pointerEvents;\n        const wasPosition = contentEl.style.position;\n        const wasHeight = contentEl.style.height;\n\n        contentEl.style.visibility = 'visible';\n        contentEl.style.pointerEvents = 'auto';\n        contentEl.style.position = 'static';\n        contentEl.style.height = 'auto';\n\n        contentEl.offsetHeight;\n\n        const topBar = 60;\n        const padding = 16;\n        const contentHeight = contentEl.scrollHeight;\n\n        contentEl.style.visibility = wasVisible;\n        contentEl.style.pointerEvents = wasPointerEvents;\n        contentEl.style.position = wasPosition;\n        contentEl.style.height = wasHeight;\n\n        return topBar + contentHeight + padding;\n      }\n    }\n    return 260;\n  };\n\n  const createTimeline = () => {\n    const navEl = navRef.current;\n    if (!navEl) return null;\n\n    gsap.set(navEl, { height: 60, overflow: 'hidden' });\n    gsap.set(cardsRef.current, { y: 50, opacity: 0 });\n\n    const tl = gsap.timeline({ paused: true });\n\n    tl.to(navEl, {\n      height: calculateHeight,\n      duration: 0.4,\n      ease\n    });\n\n    tl.to(cardsRef.current, { y: 0, opacity: 1, duration: 0.4, ease, stagger: 0.08 }, '-=0.1');\n\n    return tl;\n  };\n\n  useLayoutEffect(() => {\n    const tl = createTimeline();\n    tlRef.current = tl;\n\n    return () => {\n      tl?.kill();\n      tlRef.current = null;\n    };\n  }, [ease, items]);\n\n  useLayoutEffect(() => {\n    const handleResize = () => {\n      if (!tlRef.current) return;\n\n      if (isExpanded) {\n        const newHeight = calculateHeight();\n        gsap.set(navRef.current, { height: newHeight });\n\n        tlRef.current.kill();\n        const newTl = createTimeline();\n        if (newTl) {\n          newTl.progress(1);\n          tlRef.current = newTl;\n        }\n      } else {\n        tlRef.current.kill();\n        const newTl = createTimeline();\n        if (newTl) {\n          tlRef.current = newTl;\n        }\n      }\n    };\n\n    window.addEventListener('resize', handleResize);\n    return () => window.removeEventListener('resize', handleResize);\n  }, [isExpanded]);\n\n  const toggleMenu = () => {\n    const tl = tlRef.current;\n    if (!tl) return;\n    if (!isExpanded) {\n      setIsHamburgerOpen(true);\n      setIsExpanded(true);\n      tl.play(0);\n    } else {\n      setIsHamburgerOpen(false);\n      tl.eventCallback('onReverseComplete', () => setIsExpanded(false));\n      tl.reverse();\n    }\n  };\n\n  const setCardRef = (i: number) => (el: HTMLDivElement | null) => {\n    if (el) cardsRef.current[i] = el;\n  };\n\n  return (\n    <div className={`card-nav-container ${className}`}>\n      <nav ref={navRef} className={`card-nav ${isExpanded ? 'open' : ''}`} style={{ backgroundColor: baseColor }}>\n        <div className=\"card-nav-top\">\n          <div\n            className={`hamburger-menu ${isHamburgerOpen ? 'open' : ''}`}\n            onClick={toggleMenu}\n            onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => {\n              if (e.key === 'Enter' || e.key === ' ') {\n                e.preventDefault();\n                toggleMenu();\n              }\n            }}\n            role=\"button\"\n            aria-label={isExpanded ? 'Close menu' : 'Open menu'}\n            aria-expanded={isExpanded}\n            tabIndex={0}\n            style={{ color: menuColor || '#000' }}\n          >\n            <div className=\"hamburger-line\" />\n            <div className=\"hamburger-line\" />\n          </div>\n\n          <div className=\"logo-container\">\n            <img src={logo} alt={logoAlt} className=\"logo\" />\n          </div>\n\n          <button\n            type=\"button\"\n            className=\"card-nav-cta-button\"\n            style={{ backgroundColor: buttonBgColor, color: buttonTextColor }}\n          >\n            Get Started\n          </button>\n        </div>\n\n        <div className=\"card-nav-content\" aria-hidden={!isExpanded}>\n          {(items || []).slice(0, 3).map((item, idx) => (\n            <div\n              key={`${item.label}-${idx}`}\n              className=\"nav-card\"\n              ref={setCardRef(idx)}\n              style={{ backgroundColor: item.bgColor, color: item.textColor }}\n            >\n              <div className=\"nav-card-label\">{item.label}</div>\n              <div className=\"nav-card-links\">\n                {item.links?.map((lnk, i) => (\n                  <a key={`${lnk.label}-${i}`} className=\"nav-card-link\" href={lnk.href} aria-label={lnk.ariaLabel}>\n                    <GoArrowUpRight className=\"nav-card-link-icon\" aria-hidden=\"true\" />\n                    {lnk.label}\n                  </a>\n                ))}\n              </div>\n            </div>\n          ))}\n        </div>\n      </nav>\n    </div>\n  );\n};\n\nexport default CardNav;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"gsap@^3.13.0",
		"react-icons@^5.5.0"
	]
}