{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "glass-navigation",
  "title": "Glass Navigation",
  "description": "A pill navbar that expands into a full panel of large nav links, a tagline, and social links, with a CTA button, badges, active-page highlight, and light/dark theming.",
  "dependencies": [
    "motion",
    "clsx",
    "tailwind-merge"
  ],
  "files": [
    {
      "path": "registry/new-york/glass-navigation/glass-navigation.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { motion, AnimatePresence } from \"motion/react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nfunction cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport interface GlassNavItem {\n  label: string;\n  url: string;\n  badge?: string;\n}\n\nexport interface GlassSocialLink {\n  name: string;\n  url: string;\n}\n\nexport interface GlassNavCta {\n  text: string;\n  url: string;\n  background: string;\n  color: string;\n  height: number;\n  width: number;\n  paddingX: number;\n}\n\nexport type GlassNavColorScheme = \"auto\" | \"light\" | \"dark\";\n\nexport interface GlassNavigationProps extends Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\"> {\n  logoText?: string;\n  logoImage?: string;\n  logoUrl?: string;\n  logoHeight?: number;\n  navItems?: GlassNavItem[];\n  activePage?: string;\n  onNavClick?: (item: GlassNavItem, index: number) => void;\n  showCTA?: boolean;\n  cta?: GlassNavCta;\n  tagline?: string;\n  showTagline?: boolean;\n  socialLinks?: GlassSocialLink[];\n  colorScheme?: GlassNavColorScheme;\n  glassBackground?: string;\n  glassBorderColor?: string;\n  textColor?: string;\n  darkGlassBackground?: string;\n  darkGlassBorderColor?: string;\n  darkTextColor?: string;\n  badgeBackground?: string;\n  badgeTextColor?: string;\n  pillBorderRadius?: number;\n  panelBorderRadius?: number;\n  navFontSize?: number;\n  mobileFontSize?: number;\n  mobileBreakpoint?: number;\n  navbarHeight?: number;\n  className?: string;\n}\n\nconst HEIGHT_SPRING = { type: \"spring\" as const, damping: 30, stiffness: 320, mass: 0.8 };\n\nconst DEFAULT_NAV_ITEMS: GlassNavItem[] = [\n  { label: \"Home\", url: \"/\" },\n  { label: \"Work\", url: \"/work\" },\n  { label: \"Studio\", url: \"/studio\" },\n  { label: \"Contact\", url: \"/contact\" },\n];\n\nconst DEFAULT_CTA: GlassNavCta = {\n  text: \"Get in touch\",\n  url: \"/contact\",\n  background: \"radial-gradient(circle, rgba(255,255,255,0.24) 18%, #FFA220 100%)\",\n  color: \"#ffffff\",\n  height: 36,\n  width: 0,\n  paddingX: 18,\n};\n\nconst DEFAULT_SOCIAL_LINKS: GlassSocialLink[] = [\n  { name: \"Instagram\", url: \"\" },\n  { name: \"LinkedIn\", url: \"\" },\n  { name: \"Twitter / X\", url: \"\" },\n];\n\nexport function GlassNavigation({\n  logoText = \"Brand\",\n  logoImage,\n  logoUrl = \"/\",\n  logoHeight = 26,\n  navItems = DEFAULT_NAV_ITEMS,\n  activePage = \"\",\n  onNavClick,\n  showCTA = true,\n  cta = DEFAULT_CTA,\n  tagline = \"Building digital experiences that move people forward.\",\n  showTagline = true,\n  socialLinks = DEFAULT_SOCIAL_LINKS,\n  colorScheme = \"auto\",\n  glassBackground = \"#ffffff\",\n  glassBorderColor = \"rgba(0,0,0,0.08)\",\n  textColor = \"#111111\",\n  darkGlassBackground = \"#0a0a0f\",\n  darkGlassBorderColor = \"rgba(255,255,255,0.08)\",\n  darkTextColor = \"#f2f2f2\",\n  badgeBackground = \"#6366f1\",\n  badgeTextColor = \"#ffffff\",\n  pillBorderRadius = 20,\n  panelBorderRadius = 28,\n  navFontSize = 60,\n  mobileFontSize = 36,\n  mobileBreakpoint = 560,\n  navbarHeight = 68,\n  className,\n  style,\n  ...props\n}: GlassNavigationProps) {\n  const [isOpen, setIsOpen] = React.useState(false);\n  const [hoveredNav, setHoveredNav] = React.useState<number | null>(null);\n  const [hoveredSocial, setHoveredSocial] = React.useState<number | null>(null);\n\n  const wrapRef = React.useRef<HTMLDivElement>(null);\n  const panelRef = React.useRef<HTMLDivElement>(null);\n  const [containerWidth, setContainerWidth] = React.useState(680);\n\n  React.useEffect(() => {\n    const el = wrapRef.current;\n    if (!el) return;\n    const ro = new ResizeObserver(([entry]) => setContainerWidth(entry.contentRect.width));\n    ro.observe(el);\n    return () => ro.disconnect();\n  }, []);\n\n  const isMobile = containerWidth < mobileBreakpoint;\n\n  const [systemDark, setSystemDark] = React.useState(false);\n\n  React.useEffect(() => {\n    if (colorScheme !== \"auto\") return;\n    const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n    const t = setTimeout(() => setSystemDark(mq.matches), 0);\n    const handler = (e: MediaQueryListEvent) => setSystemDark(e.matches);\n    mq.addEventListener(\"change\", handler);\n    return () => {\n      clearTimeout(t);\n      mq.removeEventListener(\"change\", handler);\n    };\n  }, [colorScheme]);\n\n  const isDark = colorScheme === \"dark\" || (colorScheme === \"auto\" && systemDark);\n\n  const bg = isDark ? darkGlassBackground : glassBackground;\n  const border = isDark ? darkGlassBorderColor : glassBorderColor;\n  const text = isDark ? darkTextColor : textColor;\n  const divider = isDark ? \"rgba(255,255,255,0.08)\" : \"rgba(0,0,0,0.08)\";\n\n  const close = React.useCallback(() => {\n    setIsOpen(false);\n    setHoveredNav(null);\n  }, []);\n\n  React.useEffect(() => {\n    if (isOpen && panelRef.current) panelRef.current.focus();\n  }, [isOpen]);\n\n  const handleNavClick = React.useCallback(\n    (item: GlassNavItem, index: number, e: React.MouseEvent<HTMLAnchorElement>) => {\n      onNavClick?.(item, index);\n      if (item.url?.startsWith(\"#\")) {\n        e.preventDefault();\n        const target = document.querySelector(item.url);\n        target?.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n      }\n      close();\n    },\n    [onNavClick, close],\n  );\n\n  const isActive = (item: GlassNavItem) => activePage !== \"\" && (item.url === activePage || item.label === activePage);\n\n  const glassStyle: React.CSSProperties = {\n    background: bg,\n    border: `1px solid ${border}`,\n  };\n\n  const items = navItems;\n  const socials = socialLinks;\n\n  const hPad = isMobile ? \"0 16px\" : \"0 24px\";\n  const cPad = isMobile ? \"4px 18px 28px\" : \"4px 32px 36px\";\n  const fontSize = isMobile ? mobileFontSize : navFontSize;\n  const letterSpacing = isMobile ? -0.5 : -2;\n  const arrowSize = isMobile ? 20 : 26;\n\n  return (\n    <div ref={wrapRef} className={cn(\"relative w-full\", className)} style={{ height: navbarHeight, ...style }} {...props}>\n      <AnimatePresence>\n        {isOpen && (\n          <motion.div\n            key=\"backdrop\"\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            transition={{ duration: 0.2 }}\n            onClick={close}\n            className=\"fixed inset-0 z-[99997]\"\n          />\n        )}\n      </AnimatePresence>\n\n      <motion.div\n        initial={false}\n        animate={{\n          borderRadius: isOpen ? panelBorderRadius : pillBorderRadius,\n          boxShadow: isOpen\n            ? isDark\n              ? \"0 20px 72px rgba(0,0,0,0.5), 0 4px 20px rgba(0,0,0,0.3)\"\n              : \"0 20px 72px rgba(0,0,0,0.14), 0 4px 20px rgba(0,0,0,0.07)\"\n            : isDark\n              ? \"0 2px 24px rgba(0,0,0,0.4)\"\n              : \"0 2px 24px rgba(0,0,0,0.07)\",\n        }}\n        transition={{\n          borderRadius: { type: \"spring\", damping: 32, stiffness: 360 },\n          boxShadow: { duration: 0.42, ease: [0.16, 1, 0.3, 1] },\n        }}\n        className=\"absolute top-0 right-0 left-0 z-[99998] overflow-hidden\"\n        style={{ ...glassStyle, borderRadius: pillBorderRadius }}\n      >\n        <div className=\"box-border flex shrink-0 items-center justify-between\" style={{ height: navbarHeight, padding: hPad }}>\n          <a href={logoUrl || \"/\"} className=\"flex items-center gap-2.5 no-underline\" onClick={close}>\n            {logoImage && <img src={logoImage} alt={logoText || \"\"} className=\"block h-auto\" style={{ height: logoHeight }} />}\n            {logoText && (\n              <span className=\"leading-none font-bold select-none\" style={{ fontSize: 18, color: text, letterSpacing: -0.3 }}>\n                {logoText}\n              </span>\n            )}\n          </a>\n\n          <div className=\"flex items-center\" style={{ gap: isMobile ? 8 : 12 }}>\n            {showCTA && cta.text && (\n              <motion.a\n                href={cta.url || \"#\"}\n                whileHover={{ scale: 1.04, opacity: 0.92 }}\n                whileTap={{ scale: 0.96 }}\n                transition={{ duration: 0.15 }}\n                className=\"box-border flex shrink-0 items-center justify-center leading-none font-semibold select-none no-underline\"\n                style={{\n                  background: cta.background,\n                  color: cta.color,\n                  height: cta.height,\n                  width: cta.width > 0 ? cta.width : \"auto\",\n                  paddingLeft: cta.paddingX,\n                  paddingRight: cta.paddingX,\n                  borderRadius: 99,\n                  fontSize: isMobile ? 12 : 13,\n                  letterSpacing: -0.2,\n                }}\n              >\n                {cta.text}\n              </motion.a>\n            )}\n\n            <motion.button\n              onClick={() => setIsOpen((o) => !o)}\n              whileTap={{ scale: 0.86 }}\n              transition={{ duration: 0.12 }}\n              aria-label={isOpen ? \"Close menu\" : \"Open menu\"}\n              aria-expanded={isOpen}\n              className=\"relative flex h-[38px] w-[38px] shrink-0 items-center justify-center border-none bg-transparent p-2 outline-none\"\n            >\n              <motion.span\n                animate={{ rotate: isOpen ? 45 : 0, y: isOpen ? 0 : -3.5 }}\n                transition={{ type: \"spring\", damping: 22, stiffness: 300 }}\n                className=\"absolute block h-[1.5px] w-[22px] rounded-[2px]\"\n                style={{ background: text }}\n              />\n              <motion.span\n                animate={{ rotate: isOpen ? -45 : 0, y: isOpen ? 0 : 3.5 }}\n                transition={{ type: \"spring\", damping: 22, stiffness: 300 }}\n                className=\"absolute block h-[1.5px] w-[22px] rounded-[2px]\"\n                style={{ background: text }}\n              />\n            </motion.button>\n          </div>\n        </div>\n\n        <motion.div initial={false} animate={{ height: isOpen ? \"auto\" : 0 }} transition={HEIGHT_SPRING} className=\"overflow-hidden\">\n          <div ref={panelRef} tabIndex={-1} onKeyDown={(e) => e.key === \"Escape\" && close()} className=\"outline-none\" aria-hidden={!isOpen}>\n            <motion.div\n              animate={{ opacity: isOpen ? 1 : 0 }}\n              transition={{ duration: isOpen ? 0.22 : 0.1, delay: isOpen ? 0.05 : 0, ease: \"easeOut\" }}\n            >\n              <div className=\"h-px\" style={{ background: divider, margin: isMobile ? \"0 18px\" : \"0 32px\" }} />\n\n              <div className=\"flex\" style={{ flexDirection: isMobile ? \"column\" : \"row\", padding: cPad }}>\n                <div className=\"flex flex-col\" style={{ flex: isMobile ? \"none\" : \"0 0 62%\", paddingRight: isMobile ? 0 : 32 }}>\n                  {items.map((item, i) => {\n                    const active = isActive(item);\n                    const dimmed = hoveredNav !== null && hoveredNav !== i;\n\n                    return (\n                      <div key={`nav-${i}`}>\n                        <motion.div\n                          animate={{ opacity: isOpen ? 1 : 0, y: isOpen ? 0 : 20 }}\n                          transition={{\n                            opacity: { duration: isOpen ? 0.3 : 0.1, delay: isOpen ? 0.08 + i * 0.055 : 0, ease: \"easeOut\" },\n                            y: { type: \"spring\", damping: 26, stiffness: 280, delay: isOpen ? 0.08 + i * 0.055 : 0 },\n                          }}\n                        >\n                          <a\n                            href={item.url || \"#\"}\n                            onClick={(e) => handleNavClick(item, i, e)}\n                            onMouseEnter={() => setHoveredNav(i)}\n                            onMouseLeave={() => setHoveredNav(null)}\n                            tabIndex={isOpen ? 0 : -1}\n                            className=\"flex items-center justify-between no-underline transition-opacity duration-[180ms] ease-[ease]\"\n                            style={{\n                              paddingTop: isMobile ? 11 : 15,\n                              paddingBottom: isMobile ? 11 : 15,\n                              opacity: dimmed ? (active ? 0.5 : 0.22) : 1,\n                            }}\n                          >\n                            <span className=\"flex min-w-0 items-center gap-2.5\">\n                              {active && <span className=\"mb-0.5 h-1.5 w-1.5 shrink-0 rounded-full\" style={{ background: text }} />}\n                              <span\n                                className=\"leading-[1.08] select-none\"\n                                style={{ fontSize, fontWeight: active ? 700 : 600, color: text, letterSpacing }}\n                              >\n                                {item.label}\n                              </span>\n                              {item.badge && (\n                                <span\n                                  className=\"mb-0.5 shrink-0 self-center rounded-full font-bold tracking-wide select-none\"\n                                  style={{\n                                    fontSize: isMobile ? 9 : 10,\n                                    background: badgeBackground,\n                                    color: badgeTextColor,\n                                    padding: \"3px 8px\",\n                                    lineHeight: 1.4,\n                                  }}\n                                >\n                                  {item.badge}\n                                </span>\n                              )}\n                            </span>\n\n                            <motion.span\n                              animate={{ opacity: hoveredNav === i ? 1 : 0, x: hoveredNav === i ? 0 : -10 }}\n                              transition={{ duration: 0.16, ease: \"easeOut\" }}\n                              className=\"shrink-0 leading-none\"\n                              style={{ fontSize: arrowSize, color: text }}\n                            >\n                              ↗\n                            </motion.span>\n                          </a>\n                        </motion.div>\n\n                        {i < items.length - 1 && <div className=\"h-px\" style={{ background: divider }} />}\n                      </div>\n                    );\n                  })}\n                </div>\n\n                <div\n                  className=\"flex flex-col justify-between\"\n                  style={{\n                    flex: isMobile ? \"none\" : 1,\n                    paddingTop: isMobile ? 0 : 20,\n                    paddingLeft: isMobile ? 0 : 32,\n                    borderLeft: isMobile ? \"none\" : `1px solid ${divider}`,\n                    borderTop: isMobile ? `1px solid ${divider}` : \"none\",\n                    marginTop: isMobile ? 4 : 0,\n                  }}\n                >\n                  {showTagline && tagline && (\n                    <motion.p\n                      animate={{ opacity: isOpen ? 0.65 : 0, y: isOpen ? 0 : 10 }}\n                      transition={{ duration: isOpen ? 0.34 : 0.1, delay: isOpen ? 0.14 : 0, ease: [0.22, 1, 0.36, 1] }}\n                      className=\"m-0 font-normal\"\n                      style={{\n                        fontSize: isMobile ? 14 : 17,\n                        lineHeight: 1.6,\n                        color: text,\n                        maxWidth: isMobile ? \"100%\" : 280,\n                        padding: isMobile ? \"16px 0 14px\" : \"0\",\n                      }}\n                    >\n                      {tagline}\n                    </motion.p>\n                  )}\n\n                  {socials.length > 0 && (\n                    <motion.div animate={{ opacity: isOpen ? 1 : 0 }} transition={{ duration: isOpen ? 0.32 : 0.1, delay: isOpen ? 0.22 : 0 }}>\n                      <div className=\"h-px\" style={{ background: divider }} />\n                      {socials.map((link, i) => (\n                        <div key={`social-${i}`}>\n                          <a\n                            href={link.url || \"#\"}\n                            target=\"_blank\"\n                            rel=\"noopener noreferrer\"\n                            tabIndex={isOpen ? 0 : -1}\n                            onMouseEnter={() => setHoveredSocial(i)}\n                            onMouseLeave={() => setHoveredSocial(null)}\n                            className=\"flex items-center justify-between font-normal no-underline transition-opacity duration-[180ms] ease-[ease]\"\n                            style={{\n                              paddingTop: isMobile ? 9 : 11,\n                              paddingBottom: isMobile ? 9 : 11,\n                              color: text,\n                              fontSize: isMobile ? 14 : 15,\n                              opacity: hoveredSocial !== null && hoveredSocial !== i ? 0.32 : 1,\n                            }}\n                          >\n                            <span className=\"select-none\">{link.name}</span>\n                            <motion.span\n                              animate={{ opacity: hoveredSocial === i ? 1 : 0, x: hoveredSocial === i ? 0 : -6 }}\n                              transition={{ duration: 0.15 }}\n                              className=\"text-[13px]\"\n                            >\n                              ↗\n                            </motion.span>\n                          </a>\n                          <div className=\"h-px\" style={{ background: divider }} />\n                        </div>\n                      ))}\n                    </motion.div>\n                  )}\n                </div>\n              </div>\n            </motion.div>\n          </div>\n        </motion.div>\n      </motion.div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}