{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "search-expand-nav",
  "type": "registry:component",
  "title": "Search-Expand Navigation Bar",
  "description": "A nav bar that expands into a search field then grows into a recent-searches card.",
  "registryDependencies": [
    "https://lab.moumen.dev/r/lab-theme.json"
  ],
  "files": [
    {
      "path": "registry/lab/search-expand-nav/search-expand-nav.tsx",
      "type": "registry:component",
      "target": "@components/lab/search-expand-nav.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useId, useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport { MotionConfig, motion } from \"motion/react\";\n\n// Search-expand navigation bar - a two-stage morph disclosure.\n//\n// Rest: a rounded bar with page icons + an avatar on the left and a search icon\n// pinned right. Click search and it plays in two stages, each animating a\n// single driving property:\n//\n//   1. Horizontal morph (open): the search icon GLIDES left to become the\n//      field's leading icon while the icons + avatar fade out, the input fades\n//      in, and a ✕ fades in on the right. The travel distance is measured from\n//      layout (offsetLeft - transform-independent), so it stays correct as the\n//      component shrinks on narrow screens.\n//   2. Vertical grow (expanded): the box - anchored to the bottom - grows\n//      UPWARD (motion animates the panel's height to auto), turning the\n//      rectangle into a card with a recent-searches panel cascading in above.\n//\n// The stages are sequenced in JS (open → grow; collapse → un-morph). \"flip\"\n// effect: the first icon rises + blurs into the search icon instead of the\n// right one travelling. Animation via motion/react; honours\n// prefers-reduced-motion. Requires the lab-theme tokens. Fully Tailwind.\n\nconst MORPH_MS = 400;\nconst GROW_MS = 420;\nconst EASE = [0.22, 1, 0.36, 1] as const;\nconst SLIDE_EASE = [0.76, 0, 0.24, 1] as const; // icon crossing: symmetric, smooth\nconst MORPH = { duration: 0.4, ease: EASE } as const;\nconst GROW = { duration: 0.44, ease: EASE } as const;\n\n// Resting chrome fade: out with a small drift + blur, back in clean.\nconst CHROME_SHOWN = { opacity: 1, x: 0, scale: 1, filter: \"blur(0px)\" };\nconst CHROME_HIDDEN = { opacity: 0, x: -6.4, scale: 0.96, filter: \"blur(3px)\" };\n\nconst ICON_BTN =\n  \"flex-none grid place-items-center w-[var(--nav-icon)] h-[var(--nav-icon)] rounded-[0.625rem] text-muted-foreground hover:bg-accent hover:text-foreground active:scale-[0.96] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\";\n\nconst MENU_ITEM =\n  \"flex items-center gap-2.5 w-full px-2 py-2 rounded-lg text-foreground/80 text-sm text-left [transition:background-color_150ms_ease,color_150ms_ease] hover:bg-accent hover:text-foreground focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-ring\";\n\nexport interface NavItem {\n  label: string;\n  icon: ReactNode;\n}\n\nexport default function SearchExpandNav({\n  nav = DEFAULT_NAV,\n  suggestions = DEFAULT_SUGGESTIONS,\n  avatar = AVATAR_URL,\n  user = \"Moumen Soliman\",\n  handle = \"@moumensoliman\",\n  effect = \"travel\",\n  inspect = false,\n  onSearch,\n}: {\n  nav?: NavItem[];\n  suggestions?: string[];\n  avatar?: string;\n  user?: string;\n  handle?: string;\n  effect?: \"travel\" | \"flip\";\n  inspect?: boolean;\n  onSearch?: (query: string) => void;\n}) {\n  const firstNav = nav[0];\n  const restNav = nav.slice(1);\n  const [open, setOpen] = useState(false);\n  const [expanded, setExpanded] = useState(false);\n  const [menuOpen, setMenuOpen] = useState(false);\n  const [travelX, setTravelX] = useState(0);\n  const rootRef = useRef<HTMLDivElement>(null);\n  const inputRef = useRef<HTMLInputElement>(null);\n  const searchBtnRef = useRef<HTMLButtonElement>(null);\n  const firstSlotRef = useRef<HTMLButtonElement>(null);\n  const accountRef = useRef<HTMLSpanElement>(null);\n  const avatarBtnRef = useRef<HTMLButtonElement>(null);\n  const menuRef = useRef<HTMLDivElement>(null);\n  const timerRef = useRef<number | null>(null);\n  const panelId = useId();\n  const menuId = useId();\n\n  const reduced = () => typeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n  // The travel distance: the search icon's resting left minus the first slot's\n  // left - offsetLeft ignores transforms, so this is safe to measure any time\n  // and re-measures as the container-query sizing kicks in.\n  useLayoutEffect(() => {\n    const measure = () => {\n      const btn = searchBtnRef.current;\n      const first = firstSlotRef.current;\n      if (!btn || !first) return;\n      setTravelX(first.offsetLeft - btn.offsetLeft);\n    };\n    measure();\n    const observer = typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(measure) : null;\n    if (rootRef.current) observer?.observe(rootRef.current);\n    return () => observer?.disconnect();\n  }, []);\n\n  function clearTimer() {\n    if (timerRef.current) {\n      clearTimeout(timerRef.current);\n      timerRef.current = null;\n    }\n  }\n\n  function openSearch() {\n    clearTimer();\n    setMenuOpen(false);\n    setOpen(true);\n    if (reduced()) setExpanded(true);\n    else timerRef.current = window.setTimeout(() => setExpanded(true), MORPH_MS);\n  }\n\n  function closeSearch() {\n    clearTimer();\n    setExpanded(false);\n    if (reduced()) setOpen(false);\n    else timerRef.current = window.setTimeout(() => setOpen(false), GROW_MS);\n  }\n\n  useEffect(() => {\n    if (expanded) inputRef.current?.focus();\n  }, [expanded]);\n\n  useEffect(() => {\n    if (inspect) {\n      setOpen(true);\n      setExpanded(true);\n    }\n  }, [inspect]);\n\n  useEffect(() => {\n    if (!open) return undefined;\n    const onPointerDown = (event: PointerEvent) => {\n      if (!rootRef.current?.contains(event.target as Node)) closeSearch();\n    };\n    const onKeyDown = (event: KeyboardEvent) => {\n      if (event.key === \"Escape\") {\n        closeSearch();\n        searchBtnRef.current?.focus();\n      }\n    };\n    document.addEventListener(\"pointerdown\", onPointerDown);\n    document.addEventListener(\"keydown\", onKeyDown);\n    return () => {\n      document.removeEventListener(\"pointerdown\", onPointerDown);\n      document.removeEventListener(\"keydown\", onKeyDown);\n    };\n  }, [open]);\n\n  useEffect(() => {\n    if (!menuOpen) return undefined;\n    menuRef.current?.querySelector<HTMLElement>('[role=\"menuitem\"]')?.focus();\n    const onPointerDown = (event: PointerEvent) => {\n      if (!accountRef.current?.contains(event.target as Node)) setMenuOpen(false);\n    };\n    const onKeyDown = (event: KeyboardEvent) => {\n      if (event.key === \"Escape\") {\n        setMenuOpen(false);\n        avatarBtnRef.current?.focus();\n      }\n    };\n    document.addEventListener(\"pointerdown\", onPointerDown);\n    document.addEventListener(\"keydown\", onKeyDown);\n    return () => {\n      document.removeEventListener(\"pointerdown\", onPointerDown);\n      document.removeEventListener(\"keydown\", onKeyDown);\n    };\n  }, [menuOpen]);\n\n  useEffect(() => clearTimer, []);\n\n  function handleSubmit(event: React.FormEvent) {\n    event.preventDefault();\n    onSearch?.(inputRef.current?.value ?? \"\");\n  }\n\n  function pickSuggestion(value: string) {\n    if (inputRef.current) inputRef.current.value = value;\n    inputRef.current?.focus();\n    onSearch?.(value);\n  }\n\n  const chrome = (hidden: boolean) => ({\n    initial: false as const,\n    animate: hidden ? CHROME_HIDDEN : CHROME_SHOWN,\n    transition: MORPH,\n    style: { pointerEvents: hidden ? (\"none\" as const) : undefined },\n  });\n\n  return (\n    <MotionConfig reducedMotion=\"user\">\n      <div\n        ref={rootRef}\n        className=\"relative w-[22rem] max-w-full h-14 [container-type:inline-size]\"\n        data-menu={menuOpen ? \"true\" : \"false\"}\n      >\n        <div\n          className={`group/nav absolute inset-x-0 bottom-0 flex flex-col bg-card rounded-xl shadow-border [--nav-icon:2.25rem] [--nav-pad:0.5rem] [--nav-avatar:2rem] @max-[330px]:[--nav-icon:1.9rem] @max-[330px]:[--nav-pad:0.375rem] @max-[330px]:[--nav-avatar:1.7rem]${\n            inspect ? \" outline outline-[1.5px] outline-dashed outline-[#3b82f6] outline-offset-4\" : \"\"\n          }`}\n          data-menu={menuOpen ? \"true\" : \"false\"}\n        >\n          {/* Elevation on a faded overlay: a cheap opacity tween, no per-frame\n              box-shadow repaint. */}\n          <motion.span\n            className=\"absolute inset-0 rounded-[inherit] shadow-[0_18px_40px_-12px_rgba(0,0,0,0.22)] pointer-events-none\"\n            aria-hidden=\"true\"\n            initial={false}\n            animate={{ opacity: expanded ? 1 : 0 }}\n            transition={GROW}\n          />\n\n          {/* Stage 2: recent searches - motion grows the height to auto. */}\n          <motion.div\n            className=\"overflow-hidden\"\n            id={panelId}\n            role=\"region\"\n            aria-label=\"Recent searches\"\n            aria-hidden={!expanded}\n            initial={false}\n            animate={{ height: expanded ? \"auto\" : 0 }}\n            transition={GROW}\n          >\n            <div className=\"pt-3 px-2 pb-2\">\n              <motion.p\n                className=\"px-2 mb-1 text-[0.6875rem] font-semibold tracking-[0.04em] uppercase text-muted-foreground/70\"\n                initial={false}\n                animate={expanded ? { opacity: 1, filter: \"blur(0px)\" } : { opacity: 0, filter: \"blur(4px)\" }}\n                transition={GROW}\n              >\n                Recent\n              </motion.p>\n              <ul className=\"flex flex-col\">\n                {suggestions.map((value, index) => (\n                  <motion.li\n                    key={value}\n                    initial={false}\n                    // Rows cascade in as the panel opens; the close drops the\n                    // delays so the fold reads as one soft piece.\n                    animate={expanded ? { opacity: 1, y: 0, filter: \"blur(0px)\" } : { opacity: 0, y: 8, filter: \"blur(4px)\" }}\n                    transition={{ ...GROW, delay: expanded ? index * 0.04 : 0 }}\n                  >\n                    <button\n                      type=\"button\"\n                      className=\"group/sug flex items-center gap-2.5 w-full p-2 rounded-[0.625rem] text-foreground/70 text-left [transition:background-color_200ms_ease,color_200ms_ease] hover:bg-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n                      tabIndex={expanded ? 0 : -1}\n                      onClick={() => pickSuggestion(value)}\n                    >\n                      <span className=\"flex-none inline-flex text-muted-foreground/70\">\n                        <ClockIcon />\n                      </span>\n                      <span className=\"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-sm\">{value}</span>\n                      <span className=\"flex-none inline-flex text-muted-foreground/50 opacity-0 -translate-x-1 [transition:opacity_200ms_ease,transform_200ms_ease] group-hover/sug:opacity-100 group-hover/sug:translate-x-0\">\n                        <ArrowUpLeftIcon />\n                      </span>\n                    </button>\n                  </motion.li>\n                ))}\n              </ul>\n            </div>\n          </motion.div>\n\n          {/* The bar: the fixed-height bottom row of the box. */}\n          <form className=\"relative flex-none h-14\" role=\"search\" onSubmit={handleSubmit}>\n            {/* Stage 1, field: hidden at rest, revealed under the leading icon. */}\n            <motion.input\n              ref={inputRef}\n              type=\"search\"\n              className=\"absolute inset-0 w-full pl-[calc(var(--nav-pad)+var(--nav-icon)+0.25rem)] pr-[calc(var(--nav-pad)+var(--nav-icon)+0.25rem)] bg-transparent border-0 outline-none text-[0.9375rem] text-foreground placeholder:text-muted-foreground/70 [&::-webkit-search-cancel-button]:appearance-none\"\n              placeholder=\"Search…\"\n              aria-label=\"Search\"\n              aria-hidden={!open}\n              tabIndex={open ? 0 : -1}\n              initial={false}\n              animate={open ? { opacity: 1, x: 0 } : { opacity: 0, x: 8 }}\n              transition={MORPH}\n              style={{ pointerEvents: open ? \"auto\" : \"none\" }}\n            />\n\n            <div className=\"absolute inset-0 flex items-center justify-between px-[var(--nav-pad)]\">\n              {firstNav && (\n                <motion.button\n                  ref={firstSlotRef}\n                  type=\"button\"\n                  className=\"flex-none grid place-items-center w-[var(--nav-icon)] h-[var(--nav-icon)] rounded-[0.625rem] overflow-hidden text-muted-foreground hover:bg-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n                  aria-label={open && effect === \"flip\" ? \"Search\" : firstNav.label}\n                  title={firstNav.label}\n                  aria-hidden={open && effect !== \"flip\" ? true : undefined}\n                  tabIndex={open && effect !== \"flip\" ? -1 : 0}\n                  initial={false}\n                  animate={open && effect === \"travel\" ? CHROME_HIDDEN : CHROME_SHOWN}\n                  transition={MORPH}\n                  style={{ pointerEvents: open && effect === \"travel\" ? \"none\" : undefined }}\n                  onClick={(event) => {\n                    if (open && effect === \"flip\") {\n                      event.preventDefault();\n                      onSearch?.(inputRef.current?.value ?? \"\");\n                    }\n                  }}\n                >\n                  {/* Both faces share one grid cell; open rises the home out and\n                      the search in - a crossfade-in-motion, no 3D backface. */}\n                  <motion.span\n                    className=\"[grid-area:1/1] inline-flex\"\n                    initial={false}\n                    animate={open && effect === \"flip\" ? { opacity: 0, y: -11.2, filter: \"blur(4px)\" } : { opacity: 1, y: 0, filter: \"blur(0px)\" }}\n                    transition={MORPH}\n                  >\n                    {firstNav.icon}\n                  </motion.span>\n                  <motion.span\n                    className=\"[grid-area:1/1] inline-flex text-foreground\"\n                    aria-hidden=\"true\"\n                    initial={false}\n                    animate={open && effect === \"flip\" ? { opacity: 1, y: 0, filter: \"blur(0px)\" } : { opacity: 0, y: 11.2, filter: \"blur(4px)\" }}\n                    transition={MORPH}\n                  >\n                    <SearchIcon />\n                  </motion.span>\n                </motion.button>\n              )}\n\n              {restNav.map((item) => (\n                <motion.button\n                  key={item.label}\n                  type=\"button\"\n                  className={ICON_BTN}\n                  aria-label={item.label}\n                  title={item.label}\n                  aria-hidden={open || undefined}\n                  tabIndex={open ? -1 : 0}\n                  {...chrome(open)}\n                >\n                  {item.icon}\n                </motion.button>\n              ))}\n\n              <motion.span className=\"relative flex-none inline-flex\" ref={accountRef} {...chrome(open)}>\n                <button\n                  ref={avatarBtnRef}\n                  type=\"button\"\n                  className=\"block rounded-[0.625rem] active:scale-[0.96] [transition:scale_150ms_ease-out] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n                  aria-label=\"Account\"\n                  aria-haspopup=\"menu\"\n                  aria-expanded={menuOpen}\n                  aria-controls={menuId}\n                  aria-hidden={open || undefined}\n                  tabIndex={open ? -1 : 0}\n                  onClick={() => setMenuOpen((value) => !value)}\n                >\n                  {/* eslint-disable-next-line @next/next/no-img-element */}\n                  <img\n                    src={avatar}\n                    alt={user}\n                    width=\"32\"\n                    height=\"32\"\n                    loading=\"lazy\"\n                    className=\"block w-[var(--nav-avatar)] h-[var(--nav-avatar)] rounded-[0.625rem] object-cover outline outline-1 -outline-offset-1 outline-foreground/10 [transition:outline-color_200ms_ease,box-shadow_200ms_ease] group-data-[menu=true]/nav:outline-ring group-data-[menu=true]/nav:shadow-[0_0_0_3px_rgba(17,17,17,0.08)]\"\n                  />\n                </button>\n\n                {/* The dropdown: opens UPWARD, scaling out of its bottom-right corner. */}\n                <motion.div\n                  className=\"absolute bottom-[calc(100%+0.625rem)] right-0 w-52 p-1.5 bg-popover rounded-[0.875rem] shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_12px_32px_-8px_rgba(0,0,0,0.22)] origin-bottom-right z-20\"\n                  id={menuId}\n                  ref={menuRef}\n                  role=\"menu\"\n                  aria-label=\"Account\"\n                  initial={false}\n                  animate={menuOpen ? { opacity: 1, y: 0, scale: 1 } : { opacity: 0, y: 6.4, scale: 0.96 }}\n                  transition={{ duration: 0.2, ease: EASE }}\n                  style={{ pointerEvents: menuOpen ? \"auto\" : \"none\" }}\n                >\n                  <div className=\"flex items-center gap-2.5 px-2 pt-2 pb-2.5\">\n                    {/* eslint-disable-next-line @next/next/no-img-element */}\n                    <img src={avatar} alt=\"\" width=\"36\" height=\"36\" loading=\"lazy\" className=\"flex-none w-9 h-9 rounded-lg object-cover outline outline-1 -outline-offset-1 outline-foreground/10\" />\n                    <span className=\"flex flex-col min-w-0\">\n                      <span className=\"text-sm font-semibold text-foreground leading-tight\">{user}</span>\n                      <span className=\"text-xs text-muted-foreground/70 leading-snug overflow-hidden text-ellipsis whitespace-nowrap\">{handle}</span>\n                    </span>\n                  </div>\n                  <div className=\"h-px bg-border my-1\" aria-hidden=\"true\" />\n                  <button type=\"button\" role=\"menuitem\" className={MENU_ITEM} tabIndex={menuOpen ? 0 : -1} onClick={() => setMenuOpen(false)}>\n                    <UserIcon /> View profile\n                  </button>\n                  <button type=\"button\" role=\"menuitem\" className={MENU_ITEM} tabIndex={menuOpen ? 0 : -1} onClick={() => setMenuOpen(false)}>\n                    <GearIcon /> Settings\n                  </button>\n                  <div className=\"h-px bg-border my-1\" aria-hidden=\"true\" />\n                  <button\n                    type=\"button\"\n                    role=\"menuitem\"\n                    className={`${MENU_ITEM} text-destructive hover:!bg-destructive/10 hover:!text-destructive`}\n                    tabIndex={menuOpen ? 0 : -1}\n                    onClick={() => setMenuOpen(false)}\n                  >\n                    <LogOutIcon /> Sign out\n                  </button>\n                </motion.div>\n              </motion.span>\n\n              {/* The travelling search icon: slides left by the measured\n                  distance to become the field's leading icon. */}\n              <motion.button\n                ref={searchBtnRef}\n                type={open ? \"submit\" : \"button\"}\n                className={`relative z-[2] flex-none grid place-items-center w-[var(--nav-icon)] h-[var(--nav-icon)] rounded-[0.625rem] [transition:color_200ms_ease] hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring ${\n                  open && effect === \"travel\" ? \"text-muted-foreground\" : \"text-foreground\"\n                }${inspect && effect === \"travel\" ? \" outline outline-[1.5px] outline-dashed outline-[#ef4444]\" : \"\"}`}\n                aria-label=\"Search\"\n                aria-expanded={open}\n                aria-controls={panelId}\n                initial={false}\n                animate={\n                  effect === \"travel\"\n                    ? { x: open ? travelX : 0, opacity: 1, scale: 1, filter: \"blur(0px)\" }\n                    : open\n                      ? { x: 0, opacity: 0, scale: 0.9, filter: \"blur(3px)\" }\n                      : { x: 0, opacity: 1, scale: 1, filter: \"blur(0px)\" }\n                }\n                transition={{ x: { duration: 0.4, ease: SLIDE_EASE }, default: MORPH }}\n                style={{ pointerEvents: open && effect === \"flip\" ? \"none\" : undefined }}\n                onClick={(event) => {\n                  if (!open) {\n                    event.preventDefault();\n                    openSearch();\n                  }\n                }}\n              >\n                <SearchIcon />\n              </motion.button>\n            </div>\n\n            {/* ✕ fades in on the right once the search icon has vacated it. */}\n            <motion.button\n              type=\"button\"\n              className=\"absolute top-1/2 right-[var(--nav-pad)] z-[2] grid place-items-center w-[var(--nav-icon)] h-[var(--nav-icon)] rounded-[0.625rem] text-muted-foreground [transition:background-color_200ms_ease,color_200ms_ease] hover:bg-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n              aria-label=\"Close search\"\n              tabIndex={open ? 0 : -1}\n              initial={false}\n              animate={open ? { opacity: 1, scale: 1 } : { opacity: 0, scale: 0.6 }}\n              transition={MORPH}\n              style={{ y: \"-50%\", pointerEvents: open ? \"auto\" : \"none\" }}\n              onClick={closeSearch}\n            >\n              <CloseIcon />\n            </motion.button>\n          </form>\n\n          {inspect && (\n            <>\n              <span className=\"absolute -top-[1.85rem] left-0 whitespace-nowrap rounded-[0.25rem] border border-[#bfdbfe] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal text-[#2563eb] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none\">\n                fixed width · bottom-anchored · grows ↑\n              </span>\n              <span className=\"absolute top-3 right-2 whitespace-nowrap rounded-[0.25rem] border border-[#bfdbfe] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal text-[#2563eb] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none\">\n                height 0 → auto\n              </span>\n              <span className=\"absolute -bottom-[1.6rem] left-0 whitespace-nowrap rounded-[0.25rem] border border-[#fecaca] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal text-[#dc2626] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none\">\n                {effect === \"flip\" ? \"home ↑ blur out · search ↑ blur in\" : `slides ← ${Math.round(travelX)}px measured`}\n              </span>\n            </>\n          )}\n        </div>\n      </div>\n    </MotionConfig>\n  );\n}\n\nconst AVATAR_URL = \"https://avatars.githubusercontent.com/u/24474287?v=4\";\n\nfunction Svg({ children, size = 20 }: { children: ReactNode; size?: number }) {\n  return (\n    <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n      {children}\n    </svg>\n  );\n}\nfunction HomeIcon() { return <Svg><path d=\"M3 10.5 12 3l9 7.5\" /><path d=\"M5 9.5V21h14V9.5\" /><path d=\"M9.5 21v-6h5v6\" /></Svg>; }\nfunction CompassIcon() { return <Svg><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"m15.5 8.5-2 5-5 2 2-5 5-2Z\" /></Svg>; }\nfunction BellIcon() { return <Svg><path d=\"M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9\" /><path d=\"M13.7 21a2 2 0 0 1-3.4 0\" /></Svg>; }\nfunction MessageIcon() { return <Svg><path d=\"M21 11.5a8.38 8.38 0 0 1-9 8.4 9 9 0 0 1-4-.9L3 21l1.9-5a8.38 8.38 0 0 1-.9-4 8.5 8.5 0 0 1 17 0Z\" /></Svg>; }\nfunction BookmarkIcon() { return <Svg><path d=\"M6 4.5h12a1 1 0 0 1 1 1V21l-7-4-7 4V5.5a1 1 0 0 1 1-1Z\" /></Svg>; }\nfunction UserIcon() { return <Svg size={17}><circle cx=\"12\" cy=\"8\" r=\"3.5\" /><path d=\"M5 20a7 7 0 0 1 14 0\" /></Svg>; }\nfunction GearIcon() { return <Svg size={17}><circle cx=\"12\" cy=\"12\" r=\"3\" /><path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z\" /></Svg>; }\nfunction LogOutIcon() { return <Svg size={17}><path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" /><path d=\"M16 17l5-5-5-5\" /><path d=\"M21 12H9\" /></Svg>; }\nfunction SearchIcon() { return <Svg><circle cx=\"11\" cy=\"11\" r=\"7\" /><path d=\"m20 20-3.2-3.2\" /></Svg>; }\nfunction CloseIcon() { return <Svg><path d=\"M18 6 6 18M6 6l12 12\" /></Svg>; }\nfunction ClockIcon() { return <Svg size={16}><circle cx=\"12\" cy=\"12\" r=\"9\" /><path d=\"M12 7v5l3 2\" /></Svg>; }\nfunction ArrowUpLeftIcon() { return <Svg size={16}><path d=\"M17 17 7 7\" /><path d=\"M7 13V7h6\" /></Svg>; }\n\nconst DEFAULT_NAV: NavItem[] = [\n  { label: \"Home\", icon: <HomeIcon /> },\n  { label: \"Explore\", icon: <CompassIcon /> },\n  { label: \"Messages\", icon: <MessageIcon /> },\n  { label: \"Bookmarks\", icon: <BookmarkIcon /> },\n  { label: \"Activity\", icon: <BellIcon /> },\n];\nconst DEFAULT_SUGGESTIONS = [\"Animations on the web\", \"flex-grow vs grid-fr\", \"prefers-reduced-motion\", \"container query units\"];\n"
    }
  ],
  "dependencies": [
    "motion"
  ]
}
