{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "design-components-folder",
  "title": "Design Components Folder",
  "author": "AlgorizeTech",
  "description": "An animated folder that opens to fan out component preview cards. Use it on portfolio and feature pages to reveal a collection on interaction.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/custom/blocks/DesignComponentsFolder.tsx",
      "content": "\"use client\";\n\nimport React, { useState, useEffect } from \"react\";\nimport {\n  ArrowRight,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { springLinear } from \"./motion-curves\";\n\n// Springs, drawn as CSS `linear()` curves: the fan-out, the retract into the\n// folder, and the lift under the pointer (the move and the scale).\nconst FAN_OUT = springLinear({ stiffness: 90, damping: 14 });\nconst RETRACT = springLinear({ stiffness: 110, damping: 15 });\nconst HOVER_MOVE = springLinear({ stiffness: 500, damping: 25 });\nconst HOVER_SCALE = springLinear({ stiffness: 550, damping: 30 });\nconst HOVER_LAYER = \"0.3s cubic-bezier(0.25, 0.1, 0.35, 1)\";\nconst timing = (spring: { duration: number; easing: string }, delay = 0) =>\n  `${spring.duration}ms ${spring.easing}${delay ? ` ${delay}s` : \"\"}`;\n\n/** Where a card starts (tucked in the folder), where it fans out to, and how it lifts. */\ninterface FanCard {\n  initX: number;\n  initY: number;\n  rotate: number;\n  delay: number;\n  zIndex: number;\n  hoverScale: number;\n  hoverRotate: number;\n}\n\n// Folder silhouette in the 660×310 viewBox: tab on the left, body below.\nconst FOLDER_PATH = `\n  M -8 8\n  C -8 3, -3 0, 8 0\n  L 330 0\n  C 347 0, 360 25, 372 45\n  C 380 58, 392 68, 408 68\n  L 638 68\n  C 644 68, 648 72, 648 80\n  L 620 302\n  C 620 307, 616 310, 610 310\n  L 30 310\n  C 24 310, 20 307, 20 302\n  Z\n`;\n\nexport interface DesignComponentsFolderProps {\n  color?: string;\n  className?: string;\n  disableLinks?: boolean;\n  /**\n   * The element used for links. Defaults to a plain `a`, so this component works\n   * in any React app with no adaptation. In Next.js, pass `next/link` to keep\n   * client-side navigation and prefetching: `linkComponent={Link}`.\n   */\n  linkComponent?: React.ElementType;\n}\n\nexport function DesignComponentsFolder({\n  color,\n  className,\n  disableLinks = false,\n  linkComponent: Link = \"a\",\n}: DesignComponentsFolderProps) {\n  const [isInView, setIsInView] = useState(false);\n  const [retractedIndex, setRetractedIndex] = useState<number | null>(null);\n\n  const getAccentColor = (col?: string) => {\n    if (!col || col === \"primary\" || col === \"default\") return undefined;\n    const presets: Record<string, string> = {\n      indigo: \"#6366f1\",\n      rose: \"#f43f5e\",\n      emerald: \"#10b981\",\n      zinc: \"#18181b\",\n    };\n    return presets[col] || col;\n  };\n\n  const resolvedColor = getAccentColor(color);\n  const customStyle: React.CSSProperties = resolvedColor\n    ? ({ \"--primary\": resolvedColor } as React.CSSProperties)\n    : {};\n\n  // The retract loop runs only while the folder is on screen: off screen it\n  // would keep re-rendering every card for nothing. It picks up at the next\n  // card when the reader scrolls back.\n  const [onScreen, setOnScreen] = useState(false);\n  const nextCardRef = React.useRef(0);\n\n  useEffect(() => {\n    if (!isInView || !onScreen) return;\n\n    let interval = 0;\n    let bringBack = 0;\n    // Start auto loop 2 seconds after the entrance fan-out (or the return).\n    const startTimer = window.setTimeout(() => {\n      interval = window.setInterval(() => {\n        // Retract card into folder\n        setRetractedIndex(nextCardRef.current);\n\n        // Bring card back out to visible state after 900ms\n        bringBack = window.setTimeout(() => {\n          setRetractedIndex(null);\n          nextCardRef.current = (nextCardRef.current + 1) % 8;\n        }, 900);\n      }, 2500);\n    }, 2000);\n\n    // Every timer is cleared here — the interval and the pending bring-back\n    // included — so leaving the screen or unmounting stops the loop cold.\n    return () => {\n      window.clearTimeout(startTimer);\n      window.clearInterval(interval);\n      window.clearTimeout(bringBack);\n      setRetractedIndex(null);\n    };\n  }, [isInView, onScreen]);\n\n  // The stage reports when it is on screen; the first time also starts the fan-out.\n  const stageRef = React.useRef<HTMLDivElement>(null);\n  useEffect(() => {\n    const el = stageRef.current;\n    if (!el) return;\n    const io = new IntersectionObserver(([entry]) => {\n      if (!entry) return;\n      if (entry.isIntersecting) {\n        setIsInView(true);\n        setOnScreen(true);\n      } else setOnScreen(false);\n    });\n    io.observe(el);\n    return () => io.disconnect();\n  }, []);\n\n  // The card under a (non-touch) pointer lifts, turns and rises above the rest.\n  const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);\n\n  // Fan-out: each card starts small and hidden down in the folder and springs\n  // out to its place after its own delay; the retract loop springs one back\n  // in. A lifted card springs to its hover pose, and settles back the way it\n  // fanned out — its delay included.\n  const cardMotion = (index: number, card: FanCard) => {\n    const state = !isInView ? \"hidden\" : retractedIndex === index ? \"retracted\" : \"visible\";\n    const tucked = state !== \"visible\";\n    const hovered = hoveredIndex === index;\n    const settle = state === \"visible\" ? timing(FAN_OUT, card.delay) : timing(RETRACT);\n    const move = hovered ? timing(HOVER_MOVE) : settle;\n    return {\n      style: {\n        translate: `${tucked ? card.initX : 0}px ${hovered ? -10 : tucked ? card.initY : 0}px`,\n        scale: hovered ? card.hoverScale : tucked ? 0.2 : 1,\n        rotate: `${hovered ? card.hoverRotate : tucked ? 0 : card.rotate}deg`,\n        opacity: tucked ? 0 : 1,\n        zIndex: hovered ? 40 : card.zIndex,\n        transition: [\n          `translate ${move}`,\n          `rotate ${move}`,\n          `scale ${hovered ? timing(HOVER_SCALE) : settle}`,\n          `opacity ${settle}`,\n          `z-index ${hovered ? HOVER_LAYER : settle}`,\n        ].join(\", \"),\n      } as React.CSSProperties,\n      onPointerEnter: (e: React.PointerEvent) => {\n        if (e.pointerType !== \"touch\") setHoveredIndex(index);\n      },\n      onPointerLeave: () => setHoveredIndex((current) => (current === index ? null : current)),\n    };\n  };\n\n  return (\n    <section style={customStyle} className={cn(\"relative w-full py-8 md:py-16 select-none flex justify-center items-center\", className)}>\n      {/* \n        Full Width Responsive Stage with Scale Wrapper to ensure cards shrink smoothly on mobile/small screens\n      */}\n      <div className=\"w-full flex justify-center items-center px-1 sm:px-0\">\n        <div\n          ref={stageRef}\n          className=\"relative w-full min-[494px]:w-[70%] sm:w-full max-w-[960px] mx-auto h-[380px] min-[450px]:h-[440px] min-[550px]:h-[500px] min-[620px]:h-[540px] sm:h-[580px] md:h-[660px] lg:h-[700px] flex items-end justify-center origin-bottom scale-[0.88] min-[400px]:scale-[0.94] min-[500px]:scale-[0.98] sm:scale-100 transition-all duration-300\"\n        >\n          {/* CARDS FANNING OUT & AUTOMATIC SEQUENTIAL RETRACTING LOOP */}\n          <div className=\"absolute inset-0 z-10 pointer-events-none\">\n            <div className=\"relative w-full h-full pointer-events-auto\">\n\n            {/* Card 0: Calendar (calendar.tsx) -> Indigo/Purple Tint */}\n            <div\n              {...cardMotion(0, { initX: 240, initY: 340, rotate: -8, delay: 0.1, zIndex: 11, hoverScale: 1.06, hoverRotate: -3 })}\n              className=\"absolute top-[26%] sm:top-[6%] left-[6%] sm:left-[10%] md:left-[14%] lg:left-[16%] w-[130px] sm:w-[210px] md:w-[280px] lg:w-[320px] h-[105px] sm:h-[165px] md:h-[210px] lg:h-[235px] rounded-2xl overflow-hidden shadow-2xl border border-indigo-500/30 cursor-pointer group bg-gradient-to-br from-indigo-500/10 via-card to-purple-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/calendar\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-indigo-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-indigo-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">calendar.tsx</span>\n                    <div className=\"size-2 rounded-full bg-indigo-500/40\" />\n                  </div>\n\n                  <div className=\"flex-1 flex flex-col justify-center items-center relative overflow-hidden w-full\">\n                    <div className=\"w-full p-1.5 rounded-xl bg-card border border-indigo-500/20 space-y-1 my-auto text-[6.5px]\">\n                      <div className=\"flex items-center justify-between border-b border-border/40 pb-0.5 px-0.5\">\n                        <div className=\"flex items-center gap-1\">\n                          <span className=\"size-1.5 rounded-full bg-indigo-500 animate-pulse\" />\n                          <span className=\"font-extrabold text-[7.5px] text-foreground\">August 2026</span>\n                        </div>\n                        <div className=\"flex items-center gap-0.5 text-muted-foreground text-[6px]\">\n                          <span className=\"size-3 rounded bg-muted/60 border border-border flex items-center justify-center font-semibold\">‹</span>\n                          <span className=\"size-3 rounded bg-muted/60 border border-border flex items-center justify-center font-semibold\">›</span>\n                        </div>\n                      </div>\n                      <div className=\"grid grid-cols-7 gap-0.5 font-extrabold text-muted-foreground/70 text-center text-[5.5px] uppercase\">\n                        <span>Su</span><span>Mo</span><span>Tu</span><span>We</span><span>Th</span><span>Fr</span><span>Sa</span>\n                      </div>\n                      <div className=\"grid grid-cols-7 gap-0.5 text-center font-semibold text-[6px] items-center\">\n                        <span className=\"text-muted-foreground/30 py-0.5\">30</span>\n                        <span className=\"text-muted-foreground/30 py-0.5\">31</span>\n                        <span className=\"py-0.5 rounded text-foreground\">1</span>\n                        <span className=\"py-0.5 rounded text-foreground\">2</span>\n                        <span className=\"py-0.5 rounded text-foreground\">3</span>\n                        <span className=\"py-0.5 rounded text-foreground\">4</span>\n                        <span className=\"py-0.5 rounded text-foreground\">5</span>\n                        <span className=\"py-0.5 rounded-l-md bg-indigo-600 text-white font-semibold\">14</span>\n                        <span className=\"py-0.5 bg-indigo-500/20 text-indigo-600 font-extrabold\">15</span>\n                        <span className=\"py-0.5 bg-indigo-500/20 text-indigo-600 font-extrabold\">16</span>\n                        <span className=\"py-0.5 rounded-r-md bg-indigo-600 text-white font-semibold\">17</span>\n                      </div>\n                    </div>\n                  </div>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-indigo-500 truncate\">\n                      Calendar\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Date Picker Grid\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-indigo-500/10 flex items-center justify-center text-indigo-500 transition-all group-hover:bg-indigo-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 1: Data Table (data-table.tsx) -> Emerald/Teal Tint */}\n            <div\n              {...cardMotion(1, { initX: 60, initY: 350, rotate: 2, delay: 0.22, zIndex: 14, hoverScale: 1.06, hoverRotate: 0 })}\n              className=\"absolute top-[24%] sm:top-[4%] left-[30%] sm:left-[34%] md:left-[38%] lg:left-[40%] w-[135px] sm:w-[215px] md:w-[290px] lg:w-[330px] h-[110px] sm:h-[170px] md:h-[215px] lg:h-[240px] rounded-2xl overflow-hidden shadow-2xl border border-emerald-500/30 cursor-pointer group bg-gradient-to-br from-emerald-500/10 via-card to-teal-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/data-table\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-emerald-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-emerald-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">data-table.tsx</span>\n                    <div className=\"size-2 rounded-full bg-emerald-500/40\" />\n                  </div>\n\n                  <div className=\"flex-1 flex flex-col justify-center items-center relative overflow-hidden w-full\">\n                    <div className=\"w-full p-1.5 rounded-xl bg-card border border-emerald-500/20 space-y-1 my-auto text-[6px]\">\n                      <div className=\"flex justify-between items-center border-b border-border/40 pb-1 px-0.5\">\n                        <div className=\"flex items-center gap-1\">\n                          <span className=\"font-extrabold text-foreground text-[6.5px]\">Invoices</span>\n                          <span className=\"px-1 py-0.2 rounded bg-emerald-500/15 text-emerald-600 font-mono text-[5px]\">128 total</span>\n                        </div>\n                      </div>\n                      <div className=\"grid grid-cols-12 gap-1 items-center bg-emerald-500/10 p-0.5 rounded border border-emerald-500/20 text-[5.5px]\">\n                        <span className=\"col-span-1 text-center text-emerald-600 font-semibold\">☑</span>\n                        <span className=\"col-span-6 font-semibold text-foreground truncate\">Alex Rivers</span>\n                        <span className=\"col-span-5 text-right font-extrabold text-emerald-500\">$1,250.00</span>\n                      </div>\n                    </div>\n                  </div>\n\n                  <span className=\"absolute top-2.5 right-2.5 text-[10px] font-extrabold px-2 py-0.5 rounded-full bg-emerald-500 text-white shadow-sm z-10\">\n                    New\n                  </span>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-emerald-500 truncate\">\n                      Data Table\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Sortable Table\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-emerald-500/10 flex items-center justify-center text-emerald-500 transition-all group-hover:bg-emerald-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 2: Map (fleet-tracker.tsx) -> Blue/Sky Tint */}\n            <div\n              {...cardMotion(2, { initX: -240, initY: 340, rotate: 12, delay: 0.34, zIndex: 11, hoverScale: 1.06, hoverRotate: 4 })}\n              className=\"absolute top-[24%] sm:top-[4%] right-[4%] sm:right-[7%] md:right-[10%] lg:right-[12%] w-[125px] sm:w-[195px] md:w-[260px] lg:w-[290px] h-[105px] sm:h-[165px] md:h-[210px] lg:h-[235px] rounded-2xl overflow-hidden shadow-2xl border border-sky-500/30 cursor-pointer group bg-gradient-to-br from-sky-500/10 via-card to-blue-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/fleet-tracker\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-sky-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-sky-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">fleet-tracker.tsx</span>\n                    <div className=\"size-2 rounded-full bg-sky-500/40\" />\n                  </div>\n\n                  <div className=\"w-full h-full rounded-lg bg-sky-500/10 border border-sky-500/20 relative flex items-center justify-center my-auto overflow-hidden\">\n                    <svg className=\"absolute inset-0 w-full h-full pointer-events-none fill-sky-500/20 stroke-sky-500/50 stroke-1\" viewBox=\"0 0 100 100\">\n                      <path d=\"M 45 10 Q 55 12, 60 20 Q 65 25, 75 30 Q 80 40, 70 50 Q 75 60, 68 75 Q 60 85, 55 90 Q 50 82, 45 78 Q 40 70, 32 65 Q 25 60, 28 50 Q 30 40, 35 30 Q 32 20, 45 10 Z\" />\n                    </svg>\n                    <div className=\"absolute top-[48%] left-[50%] z-10 -translate-x-1/2 -translate-y-1/2\">\n                      <span className=\"size-3 rounded-full bg-rose-500/30 block animate-ping absolute inset-0\" />\n                      <span className=\"size-2 rounded-full bg-rose-500 block ring-2 ring-rose-500/40 border border-white shadow-xs\" />\n                    </div>\n                    <div className=\"absolute bottom-1 left-1 px-1 py-0.2 rounded bg-background/90 border border-sky-500/30 text-[5px] font-semibold text-sky-600 shadow-2xs\">\n                      Bangladesh\n                    </div>\n                  </div>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-sky-500 truncate\">\n                      Map\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Fleet Tracker Map\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-sky-500/10 flex items-center justify-center text-sky-500 transition-all group-hover:bg-sky-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 3: Breadcrumb (breadcrumb.tsx) -> Violet/Fuchsia Tint */}\n            <div\n              {...cardMotion(3, { initX: 180, initY: 280, rotate: -4, delay: 0.46, zIndex: 16, hoverScale: 1.05, hoverRotate: -1 })}\n              className=\"absolute top-[28%] sm:top-[18%] left-[12%] sm:left-[16%] md:left-[20%] lg:left-[23%] w-[145px] sm:w-[230px] md:w-[310px] lg:w-[350px] h-[125px] sm:h-[205px] md:h-[265px] lg:h-[295px] rounded-2xl overflow-hidden shadow-2xl border border-violet-500/30 cursor-pointer group bg-gradient-to-br from-violet-500/10 via-card to-fuchsia-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/breadcrumb\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-violet-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-violet-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">breadcrumb.tsx</span>\n                    <div className=\"size-2 rounded-full bg-violet-500/40\" />\n                  </div>\n\n                  <div className=\"w-full flex items-center justify-center my-auto\">\n                    <div className=\"px-2.5 py-1.5 sm:px-3 sm:py-2 rounded-xl bg-card border border-violet-500/20 shadow-sm flex items-center gap-1 sm:gap-1.5 text-[6.5px] sm:text-[8px] font-semibold\">\n                      <span className=\"text-muted-foreground\">Docs</span>\n                      <span className=\"text-muted-foreground/50\">/</span>\n                      <span className=\"text-muted-foreground\">Components</span>\n                      <span className=\"text-muted-foreground/50\">/</span>\n                      <span className=\"text-violet-600 dark:text-violet-400 font-extrabold\">Breadcrumb</span>\n                    </div>\n                  </div>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-violet-500 truncate\">\n                      Breadcrumb\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Truncated Navigation\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-violet-500/10 flex items-center justify-center text-violet-500 transition-all group-hover:bg-violet-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 4: Dock (dock.tsx) -> Amber/Orange Tint */}\n            <div\n              {...cardMotion(4, { initX: -180, initY: 260, rotate: 4, delay: 0.7, zIndex: 18, hoverScale: 1.05, hoverRotate: 1 })}\n              className=\"absolute top-[30%] sm:top-[20%] right-[7%] sm:right-[11%] md:right-[15%] lg:right-[18%] w-[145px] sm:w-[230px] md:w-[310px] lg:w-[350px] h-[155px] sm:h-[285px] md:h-[380px] lg:h-[420px] rounded-2xl overflow-hidden shadow-2xl border border-amber-500/30 cursor-pointer group bg-gradient-to-br from-amber-500/10 via-card to-orange-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/dock\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-amber-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-amber-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">dock.tsx</span>\n                    <div className=\"size-2 rounded-full bg-amber-500/40\" />\n                  </div>\n\n                  <div className=\"w-full flex items-center justify-center my-auto\">\n                    <div className=\"px-2.5 py-1.5 rounded-2xl bg-card border border-amber-500/20 shadow-md flex items-end gap-1.5\">\n                      <div className=\"size-4 rounded-lg bg-rose-500/80 flex items-center justify-center text-[7px] text-white font-semibold\">A</div>\n                      <div className=\"size-4 rounded-lg bg-amber-500/80 flex items-center justify-center text-[7px] text-white font-semibold\">B</div>\n                      <div className=\"size-5 rounded-lg bg-amber-500 text-white flex items-center justify-center text-[9px] font-semibold shadow-sm -translate-y-1\">★</div>\n                      <div className=\"size-4 rounded-lg bg-emerald-500/80 flex items-center justify-center text-[7px] text-white font-semibold\">C</div>\n                    </div>\n                  </div>\n\n                  <span className=\"absolute top-2.5 right-2.5 text-[10px] font-extrabold px-2 py-0.5 rounded-full bg-amber-500 text-white shadow-sm z-10\">\n                    New\n                  </span>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-amber-500 truncate\">\n                      Dock\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      macOS Magnification\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-amber-500/10 flex items-center justify-center text-amber-500 transition-all group-hover:bg-amber-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 5: File Upload (file-upload.tsx) -> Rose/Pink Tint */}\n            <div\n              {...cardMotion(5, { initX: 260, initY: 250, rotate: -12, delay: 0.82, zIndex: 10, hoverScale: 1.05, hoverRotate: -6 })}\n              className=\"absolute top-[38%] sm:top-[28%] left-[2%] sm:left-[4%] md:left-[7%] lg:left-[9%] w-[125px] sm:w-[195px] md:w-[260px] lg:w-[290px] h-[145px] sm:h-[255px] md:h-[345px] lg:h-[385px] rounded-2xl overflow-hidden shadow-2xl border border-rose-500/30 cursor-pointer group bg-gradient-to-br from-rose-500/10 via-card to-pink-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/file-upload\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-rose-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-rose-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">file-upload.tsx</span>\n                    <div className=\"size-2 rounded-full bg-rose-500/40\" />\n                  </div>\n\n                  <div className=\"w-full max-w-[130px] p-2 rounded-xl bg-card border border-dashed border-rose-500/60 text-center space-y-1 my-auto mx-auto\">\n                    <span className=\"text-xs text-rose-500 font-semibold\">☁</span>\n                    <div className=\"text-[8px] font-semibold text-foreground\">Drag &amp; Drop File</div>\n                  </div>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-rose-500 truncate\">\n                      File Upload\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Drag &amp; Drop Motion\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-rose-500/10 flex items-center justify-center text-rose-500 transition-all group-hover:bg-rose-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 6: Network Graph (network-graph.tsx) -> Cyan/Blue Tint */}\n            <div\n              {...cardMotion(6, { initX: -260, initY: 250, rotate: 12, delay: 0.94, zIndex: 10, hoverScale: 1.05, hoverRotate: 6 })}\n              className=\"absolute top-[38%] sm:top-[28%] right-[1%] sm:right-[2%] md:right-[4%] lg:right-[5%] w-[125px] sm:w-[195px] md:w-[260px] lg:w-[290px] h-[145px] sm:h-[255px] md:h-[345px] lg:h-[385px] rounded-2xl overflow-hidden shadow-2xl border border-cyan-500/30 cursor-pointer group bg-gradient-to-br from-cyan-500/10 via-card to-blue-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/network-graph\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-cyan-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-1.5 sm:mb-2 group-hover:border-cyan-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">network-graph.tsx</span>\n                    <div className=\"size-2 rounded-full bg-cyan-500/40\" />\n                  </div>\n\n                  <div className=\"w-full h-full relative flex items-center justify-center p-1 my-auto overflow-hidden\">\n                    <div className=\"size-20 rounded-full border border-dashed border-cyan-500/35 absolute flex items-center justify-center pointer-events-none\">\n                      <div className=\"absolute -top-1.5 left-1/2 -translate-x-1/2 size-3 rounded-full bg-emerald-500 text-[5px] font-semibold text-white flex items-center justify-center shadow-xs\">A</div>\n                      <div className=\"absolute -bottom-1.5 left-1/2 -translate-x-1/2 size-3 rounded-full bg-amber-500 text-[5px] font-semibold text-white flex items-center justify-center shadow-xs\">B</div>\n                    </div>\n                    <div className=\"size-5 rounded-full bg-cyan-500 text-white font-semibold text-[7px] flex items-center justify-center shadow-md z-10 border-2 border-background ring-2 ring-cyan-500/20\">Core</div>\n                  </div>\n\n                  <span className=\"absolute top-2.5 right-2.5 text-[10px] font-extrabold px-2 py-0.5 rounded-full bg-cyan-500 text-white shadow-sm z-10\">\n                    New\n                  </span>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-cyan-500 truncate\">\n                      Network Graph\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Node Graph Canvas\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-cyan-500/10 flex items-center justify-center text-cyan-500 transition-all group-hover:bg-cyan-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n            {/* Card 7: Navbar (navbar.tsx) -> Purple/Primary Tint */}\n            <div\n              {...cardMotion(7, { initX: 60, initY: 250, rotate: 1, delay: 0.58, zIndex: 28, hoverScale: 1.06, hoverRotate: 0 })}\n              className=\"absolute top-[36%] sm:top-[28%] left-[24%] sm:left-[28%] md:left-[33%] lg:left-[36%] w-[135px] sm:w-[215px] md:w-[290px] lg:w-[330px] h-[125px] sm:h-[205px] md:h-[265px] lg:h-[295px] rounded-2xl overflow-hidden shadow-2xl border border-purple-500/30 cursor-pointer group bg-gradient-to-br from-purple-500/10 via-card to-indigo-500/10 p-2.5 sm:p-4 flex flex-col justify-between\"\n            >\n              <Link href={disableLinks ? \"#\" : \"/docs/nextjs/navbar\"} onClick={disableLinks ? (e: React.MouseEvent) => e.preventDefault() : undefined} className=\"w-full h-full flex flex-col justify-between\">\n                {/* Top: Miniature Illustration Container */}\n                <div className=\"w-full flex-1 rounded-xl border border-purple-500/20 bg-background/80 p-2 sm:p-2.5 flex flex-col justify-between overflow-hidden relative mb-2 group-hover:border-purple-500/60 transition-colors\">\n                  <div className=\"flex items-center justify-between border-b border-border/50 pb-1.5 mb-1.5 shrink-0\">\n                    <div className=\"flex items-center gap-1\">\n                      <span className=\"size-1.5 rounded-full bg-rose-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-amber-500/80 inline-block\" />\n                      <span className=\"size-1.5 rounded-full bg-emerald-500/80 inline-block\" />\n                    </div>\n                    <span className=\"text-[9px] font-mono text-muted-foreground/70 truncate max-w-[120px] font-semibold\">navbar.tsx</span>\n                    <div className=\"size-2 rounded-full bg-purple-500/40\" />\n                  </div>\n\n                  <div className=\"w-full my-auto px-0.5\">\n                    <div className=\"w-full p-1.5 rounded-xl bg-card border border-purple-500/20 flex items-center justify-between shadow-xs px-2.5\">\n                      <div className=\"flex items-center gap-1.5 text-[8.5px] font-semibold text-foreground\">\n                        <span className=\"size-2 rounded bg-purple-500\" />\n                        <span>DocsUI</span>\n                      </div>\n                      <div className=\"flex items-center gap-2 text-[7px] font-semibold text-muted-foreground\">\n                        <span>Docs</span>\n                        <span className=\"px-2 py-0.5 rounded-md bg-purple-600 text-white font-extrabold text-[6.5px]\">Login</span>\n                      </div>\n                    </div>\n                  </div>\n\n                  <span className=\"absolute top-2.5 right-2.5 text-[10px] font-extrabold px-2 py-0.5 rounded-full bg-purple-500 text-white shadow-sm z-10\">\n                    Core\n                  </span>\n                </div>\n\n                {/* Bottom: Card Info & Arrow */}\n                <div className=\"flex items-center justify-between pt-1 shrink-0\">\n                  <div className=\"min-w-0 pr-1\">\n                    <h4 className=\"text-xs sm:text-sm font-semibold text-foreground transition-colors group-hover:text-purple-500 truncate\">\n                      Navbar\n                    </h4>\n                    <p className=\"text-[10px] sm:text-xs text-muted-foreground mt-0.5 font-medium truncate\">\n                      Responsive Header\n                    </p>\n                  </div>\n                  <div className=\"size-6 sm:size-7 rounded-lg bg-purple-500/10 flex items-center justify-center text-purple-500 transition-all group-hover:bg-purple-600 group-hover:text-white shrink-0\">\n                    <ArrowRight className=\"size-3.5\" />\n                  </div>\n                </div>\n              </Link>\n            </div>\n\n          </div>\n        </div>\n\n        {/* ═══════════════════════════════════════════════\n           FOREGROUND SOLID FOLDER BOX (+50PX HEIGHT, TIGHTER CORNERS)\n           ═══════════════════════════════════════════════ */}\n        <div className=\"absolute bottom-0 w-[90%] sm:w-[82%] md:w-[620px] lg:w-[720px] h-[210px] min-[420px]:h-[250px] min-[520px]:h-[290px] sm:h-[330px] md:h-[400px] lg:h-[440px] z-30 pointer-events-none\">\n          <div className=\"relative w-full h-full\">\n            {/* Folder Box */}\n            <div className=\"absolute inset-0\">\n              <svg\n                className=\"w-full h-full relative z-10\"\n                viewBox=\"-10 0 660 310\"\n                preserveAspectRatio=\"none\"\n              >\n                <defs>\n                  {/* Fully opaque so the cards tucked behind the folder never show\n                      through; a faint white wash keeps the top-left highlight. */}\n                  <linearGradient id=\"themeFolderGradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                    <stop offset=\"0%\" stopColor=\"#ffffff\" stopOpacity=\"0.14\" />\n                    <stop offset=\"50%\" stopColor=\"#ffffff\" stopOpacity=\"0.06\" />\n                    <stop offset=\"100%\" stopColor=\"#ffffff\" stopOpacity=\"0\" />\n                  </linearGradient>\n                </defs>\n                {/* A soft tint of the colour, not the colour itself — the same\n                    OKLCH recipe as Folder, so every theme reads light and calm. */}\n                <path\n                  d={FOLDER_PATH}\n                  fill=\"oklch(from var(--primary) 0.88 calc(c * 0.4) h)\"\n                  stroke=\"rgba(255, 255, 255, 0.45)\"\n                  strokeWidth=\"2\"\n                />\n                <path d={FOLDER_PATH} fill=\"url(#themeFolderGradient)\" />\n              </svg>\n            </div>\n\n            {/* Folder Text Content Overlay */}\n            <div className=\"absolute inset-0 p-8 sm:p-12 md:p-16 lg:p-20 flex flex-col justify-end pointer-events-auto\">\n              <div className=\"relative z-10\">\n                <h3\n                  className=\"text-3xl sm:text-5xl md:text-6xl lg:text-7xl font-semibold tracking-tight leading-[1.05]\"\n                  // Deep ink of the same hue, readable on the light tint.\n                  style={{ color: \"oklch(from var(--primary) 0.32 calc(c * 0.6) h)\" }}\n                >\n                  Design<br />Components\n                </h3>\n              </div>\n            </div>\n\n          </div>\n        </div>\n\n      </div>\n      </div>\n    </section>\n  );\n}\n\nexport default DesignComponentsFolder;\n",
      "type": "registry:component",
      "target": "components/custom/blocks/DesignComponentsFolder.tsx"
    },
    {
      "path": "src/components/custom/blocks/motion-curves.ts",
      "content": "/**\n * Motion curves with no animation library behind them.\n *\n * The components here ship as CSS, GSAP or Motion builds that must move\n * identically, so the curves are computed once, from the same numbers, and\n * handed to whichever engine runs them:\n *\n *   - `cubicBezier(x1, y1, x2, y2)` → an easing function (GSAP accepts any\n *     `(progress) => value` as `ease`), exact for Motion's `ease: [..]` arrays\n *     and for CSS `cubic-bezier()`.\n *   - `spring({ stiffness, damping, mass })` → the analytic solution Motion\n *     Motion uses, as an easing function plus the time it takes to settle, or\n *     as a CSS `linear()` string for a fixed start and end.\n *   - `createSpringFollower` → a value that chases a moving target through the\n *     same spring every frame, like Motion's `useSpring`, for pointer-driven\n *     motion that no fixed curve can describe.\n */\n\n// ---------------------------------------------------------------------------\n// Cubic bezier\n// ---------------------------------------------------------------------------\n\n/**\n * The CSS / Motion cubic-bezier as a function of progress. Newton-Raphson\n * with a bisection fallback, the same solver browsers use.\n */\nexport function cubicBezier(x1: number, y1: number, x2: number, y2: number) {\n  if (x1 === y1 && x2 === y2) return (t: number) => t;\n\n  const a = (p1: number, p2: number) => 1 - 3 * p2 + 3 * p1;\n  const b = (p1: number, p2: number) => 3 * p2 - 6 * p1;\n  const c = (p1: number) => 3 * p1;\n  const at = (t: number, p1: number, p2: number) =>\n    ((a(p1, p2) * t + b(p1, p2)) * t + c(p1)) * t;\n  const slope = (t: number, p1: number, p2: number) =>\n    3 * a(p1, p2) * t * t + 2 * b(p1, p2) * t + c(p1);\n\n  const solveX = (x: number) => {\n    let t = x;\n    for (let i = 0; i < 8; i++) {\n      const s = slope(t, x1, x2);\n      if (Math.abs(s) < 1e-6) break;\n      const err = at(t, x1, x2) - x;\n      if (Math.abs(err) < 1e-7) return t;\n      t -= err / s;\n    }\n    let lo = 0;\n    let hi = 1;\n    t = x;\n    for (let i = 0; i < 30 && hi - lo > 1e-7; i++) {\n      const value = at(t, x1, x2);\n      if (value < x) lo = t;\n      else hi = t;\n      t = (lo + hi) / 2;\n    }\n    return t;\n  };\n\n  return (x: number) => (x <= 0 ? 0 : x >= 1 ? 1 : at(solveX(x), y1, y2));\n}\n\n/** Motion's named eases, as the cubic-beziers they are. */\nexport const MOTION_EASE = {\n  linear: [0, 0, 1, 1],\n  easeIn: [0.42, 0, 1, 1],\n  easeOut: [0, 0, 0.58, 1],\n  easeInOut: [0.42, 0, 0.58, 1],\n  circIn: [0.55, 0, 1, 0.45],\n  circOut: [0.55, 0, 0.45, 1],\n  circInOut: [0.85, 0, 0.15, 1],\n  backIn: [0.31, 0.01, 0.66, -0.59],\n  backOut: [0.33, 1.53, 0.69, 0.99],\n  anticipate: [0.66, -0.56, 0.34, 1.35],\n} as const;\n\n/**\n * Motion's default layout transition (`layout` / `layoutId`):\n * `{ duration: 0.45, ease: [0.4, 0, 0.1, 1] }`.\n */\nexport const LAYOUT_TRANSITION = { duration: 0.45, ease: [0.4, 0, 0.1, 1] as const };\n\n// ---------------------------------------------------------------------------\n// Spring\n// ---------------------------------------------------------------------------\n\nexport interface SpringOptions {\n  /** Motion default 100. */\n  stiffness?: number;\n  /** Motion default 10. */\n  damping?: number;\n  /** Motion default 1. */\n  mass?: number;\n  /** Starting velocity, in units of the whole distance per second. */\n  velocity?: number;\n  /** How close to the end counts as settled, as a fraction of the distance. */\n  restDelta?: number;\n}\n\n/**\n * Normalised position (0 → 1) of a spring released from 0 towards 1, at time\n * `t` seconds. The closed-form solution Motion's `spring()` generator\n * uses for the under-, critically and over-damped cases.\n */\nexport function springAt(options: SpringOptions = {}) {\n  const { stiffness = 100, damping = 10, mass = 1, velocity = 0 } = options;\n  const zeta = damping / (2 * Math.sqrt(stiffness * mass));\n  const omega0 = Math.sqrt(stiffness / mass);\n  // Motion's convention: distance still to cover, velocity toward it negated.\n  const delta = 1;\n  const v0 = -velocity;\n\n  if (zeta < 1) {\n    const omegaD = omega0 * Math.sqrt(1 - zeta * zeta);\n    return (t: number) => {\n      const envelope = Math.exp(-zeta * omega0 * t);\n      return (\n        1 -\n        envelope *\n          (((v0 + zeta * omega0 * delta) / omegaD) * Math.sin(omegaD * t) +\n            delta * Math.cos(omegaD * t))\n      );\n    };\n  }\n  if (zeta === 1) {\n    return (t: number) => 1 - Math.exp(-omega0 * t) * (delta + (v0 + omega0 * delta) * t);\n  }\n  const omegaD = omega0 * Math.sqrt(zeta * zeta - 1);\n  return (t: number) => {\n    const envelope = Math.exp(-zeta * omega0 * t);\n    const freq = Math.min(omegaD * t, 300);\n    return (\n      1 -\n      (envelope *\n        ((v0 + zeta * omega0 * delta) * Math.sinh(freq) + omegaD * delta * Math.cosh(freq))) /\n        omegaD\n    );\n  };\n}\n\n/** Seconds until the spring stays within `restDelta` of its end. */\nexport function springDuration(options: SpringOptions = {}) {\n  const at = springAt(options);\n  const restDelta = options.restDelta ?? 0.001;\n  const step = 1 / 240;\n  let lastOutside = 0;\n  for (let t = 0; t <= 10; t += step) {\n    if (Math.abs(1 - at(t)) > restDelta) lastOutside = t;\n    else if (t - lastOutside > 0.1) break;\n  }\n  return Math.max(lastOutside + step, step);\n}\n\n/**\n * A spring as a duration and an easing function over it — what GSAP takes:\n *\n *   const { duration, ease } = springEase({ stiffness: 300, damping: 20 });\n *   gsap.to(el, { y: 0, duration, ease });\n *\n * Exact for a fixed start and end; a spring that has to react mid-flight to a\n * new target needs `createSpringFollower` instead.\n */\nexport function springEase(options: SpringOptions = {}) {\n  const duration = springDuration(options);\n  const at = springAt(options);\n  return {\n    duration,\n    ease: (progress: number) => (progress >= 1 ? 1 : at(progress * duration)),\n  };\n}\n\n/**\n * A spring as a CSS `linear()` easing and its duration in ms, for\n * `transition` / `animation` with a fixed start and end.\n *\n *   const { easing, duration } = springLinear({ stiffness: 400, damping: 30 });\n *   el.style.transition = `transform ${duration}ms ${easing}`;\n */\nexport function springLinear(options: SpringOptions = {}, pointsPerSecond = 60) {\n  const duration = springDuration(options);\n  const at = springAt(options);\n  const count = Math.max(Math.ceil(duration * pointsPerSecond), 8);\n  const points: string[] = [];\n  for (let i = 0; i <= count; i++) {\n    const t = (i / count) * duration;\n    points.push(String(Math.round((i === count ? 1 : at(t)) * 10000) / 10000));\n  }\n  return { easing: `linear(${points.join(\", \")})`, duration: Math.round(duration * 1000) };\n}\n\n// ---------------------------------------------------------------------------\n// Spring follower (useSpring equivalent)\n// ---------------------------------------------------------------------------\n\n/** Something that calls back once per frame with the time since the last, in ms. */\nexport interface FrameTicker {\n  add: (callback: (deltaMs: number) => void) => () => void;\n}\n\n/** requestAnimationFrame as a ticker — the library-free default. */\nexport const rafTicker: FrameTicker = {\n  add(callback) {\n    let last = performance.now();\n    let frame = requestAnimationFrame(function tick(now) {\n      callback(now - last);\n      last = now;\n      frame = requestAnimationFrame(tick);\n    });\n    return () => cancelAnimationFrame(frame);\n  },\n};\n\nexport interface SpringFollower {\n  /** Chase a new target from wherever the value is now, keeping its velocity. */\n  set: (target: number) => void;\n  /** Move to a value instantly, with no motion. */\n  jump: (value: number) => void;\n  get: () => number;\n  destroy: () => void;\n}\n\n/**\n * A value that follows its target through a spring, integrating the same\n * equation of motion Motion's `useSpring` solves — so a pointer-driven spring\n * reads the same in every build. Runs only while moving; `onUpdate` receives\n * each new value.\n */\nexport function createSpringFollower(\n  initial: number,\n  onUpdate: (value: number) => void,\n  options: SpringOptions & { restSpeed?: number; ticker?: FrameTicker } = {},\n): SpringFollower {\n  const { stiffness = 100, damping = 10, mass = 1, ticker = rafTicker } = options;\n  const restDelta = options.restDelta ?? 0.01;\n  const restSpeed = options.restSpeed ?? 0.01;\n  let value = initial;\n  let target = initial;\n  let velocity = 0;\n  let stop: (() => void) | null = null;\n\n  const step = (deltaMs: number) => {\n    // Fixed 1ms sub-steps keep the integration stable for stiff springs and\n    // independent of the frame rate.\n    const steps = Math.min(Math.max(Math.round(deltaMs), 1), 250);\n    for (let i = 0; i < steps; i++) {\n      const force = -stiffness * (value - target) - damping * velocity;\n      velocity += (force / mass) * 0.001;\n      value += velocity * 0.001;\n    }\n    if (Math.abs(target - value) < restDelta && Math.abs(velocity) < restSpeed) {\n      value = target;\n      velocity = 0;\n      stop?.();\n      stop = null;\n    }\n    onUpdate(value);\n  };\n\n  return {\n    set(next) {\n      target = next;\n      if (!stop && value !== target) stop = ticker.add(step);\n    },\n    jump(next) {\n      stop?.();\n      stop = null;\n      value = target = next;\n      velocity = 0;\n      onUpdate(value);\n    },\n    get: () => value,\n    destroy() {\n      stop?.();\n      stop = null;\n    },\n  };\n}\n",
      "type": "registry:component",
      "target": "components/custom/blocks/motion-curves.ts"
    }
  ],
  "docs": "Named export: DesignComponentsFolder. Motion drives the open and card-fan animation; `color` tints the folder. Uses next/image, so it needs edits outside Next.js. For the empty folder shape, use `design-folder-box`.",
  "categories": [
    "media",
    "marketing"
  ],
  "type": "registry:component"
}
