{"$schema":"https://ui.shadcn.com/schema/registry.json","author":"Kaiyu Hsu <uicapsule@kyh.io>","categories":["pages","minimal"],"dependencies":["@base-ui/react","@icons-pack/react-simple-icons","@radix-ui/react-use-controllable-state","cn","lucide-react","motion"],"description":"Dark emerald AI landing page template — hero demo types a question, reveals collapsible chain-of-thought steps and a sourced answer; feature cards, integrations marquee.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { createContext, memo, use, useMemo } from \"react\";\nimport { useControllableState } from \"@radix-ui/react-use-controllable-state\";\nimport { Collapsible as CollapsiblePrimitive } from \"@base-ui/react/collapsible\";\nimport { cn } from \"cn\";\nimport { BrainIcon, DotIcon } from \"lucide-react\";\n\nconst Collapsible = CollapsiblePrimitive.Root;\nconst CollapsibleTrigger = CollapsiblePrimitive.Trigger;\nconst CollapsibleContent = CollapsiblePrimitive.Panel;\n\ninterface ChainOfThoughtContextValue {\n  isOpen: boolean;\n  setIsOpen: (open: boolean) => void;\n}\n\nconst ChainOfThoughtContext = createContext<ChainOfThoughtContextValue | null>(null);\n\nconst useChainOfThought = () => {\n  const context = use(ChainOfThoughtContext);\n  if (!context) {\n    throw new Error(\"ChainOfThought components must be used within ChainOfThought\");\n  }\n  return context;\n};\n\nexport type ChainOfThoughtProps = ComponentProps<\"div\"> & {\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n};\n\nconst ChainOfThoughtRoot = ({\n  className,\n  open,\n  defaultOpen = false,\n  onOpenChange,\n  children,\n  ...props\n}: ChainOfThoughtProps) => {\n  const [isOpen, setIsOpen] = useControllableState({\n    defaultProp: defaultOpen,\n    onChange: onOpenChange,\n    prop: open,\n  });\n\n  const contextValue = useMemo(() => ({ isOpen, setIsOpen }), [isOpen, setIsOpen]);\n\n  return (\n    <ChainOfThoughtContext.Provider value={contextValue}>\n      <div className={cn(\"not-prose max-w-prose space-y-4\", className)} {...props}>\n        {children}\n      </div>\n    </ChainOfThoughtContext.Provider>\n  );\n};\n\nexport const ChainOfThought = memo(ChainOfThoughtRoot);\n\nexport type ChainOfThoughtHeaderProps = ComponentProps<typeof CollapsibleTrigger>;\n\nconst ChainOfThoughtHeaderBase = ({ className, children, ...props }: ChainOfThoughtHeaderProps) => {\n  const { isOpen, setIsOpen } = useChainOfThought();\n\n  return (\n    <Collapsible onOpenChange={setIsOpen} open={isOpen}>\n      <CollapsibleTrigger\n        className={cn(\n          \"text-(--muted-foreground) flex w-full items-center gap-2 text-sm transition-colors\",\n          className,\n        )}\n        {...props}\n      >\n        <BrainIcon className=\"size-4\" />\n        <span className=\"flex-1 text-left\">{children ?? \"Chain of Thought\"}</span>\n      </CollapsibleTrigger>\n    </Collapsible>\n  );\n};\n\nexport const ChainOfThoughtHeader = memo(ChainOfThoughtHeaderBase);\n\nconst stepStatusStyles = {\n  active: \"text-emerald-600\",\n  complete: \"text-(--muted-foreground)\",\n  pending: \"text-(--muted-foreground)/50\",\n};\n\nexport type ChainOfThoughtStepProps = ComponentProps<\"div\"> & {\n  icon?: ReactNode;\n  label: string;\n  status?: keyof typeof stepStatusStyles;\n};\n\nconst ChainOfThoughtStepBase = ({\n  className,\n  icon,\n  label,\n  status = \"complete\",\n  children,\n  ...props\n}: ChainOfThoughtStepProps) => (\n  <div\n    className={cn(\n      \"flex gap-2 text-sm\",\n      stepStatusStyles[status],\n      \"fade-in-0 slide-in-from-top-2 animate-in\",\n      className,\n    )}\n    {...props}\n  >\n    <div className=\"relative mt-0.5\">\n      {icon ?? <DotIcon className=\"size-4\" />}\n      <div className=\"bg-(--border) absolute top-7 bottom-0 left-1/2 -mx-px w-px\" />\n    </div>\n    <div className=\"flex-1 space-y-2\">\n      <div>{label}</div>\n      {children}\n    </div>\n  </div>\n);\n\nexport const ChainOfThoughtStep = memo(ChainOfThoughtStepBase);\n\nexport type ChainOfThoughtContentProps = ComponentProps<typeof CollapsibleContent>;\n\nconst ChainOfThoughtContentBase = ({\n  className,\n  children,\n  ...props\n}: ChainOfThoughtContentProps) => {\n  const { isOpen } = useChainOfThought();\n\n  return (\n    <Collapsible open={isOpen}>\n      <CollapsibleContent\n        className={cn(\n          \"mt-2 space-y-3\",\n          \"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-(--popover-foreground) data-[state=closed]:animate-out data-[state=open]:animate-in outline-none\",\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </CollapsibleContent>\n    </Collapsible>\n  );\n};\n\nexport const ChainOfThoughtContent = memo(ChainOfThoughtContentBase);\n\nChainOfThought.displayName = \"ChainOfThought\";\nChainOfThoughtHeader.displayName = \"ChainOfThoughtHeader\";\nChainOfThoughtStep.displayName = \"ChainOfThoughtStep\";\nChainOfThoughtContent.displayName = \"ChainOfThoughtContent\";\n","path":"/_components/chain-of-thought.tsx","target":"uicapsule/emerald-template/_components/chain-of-thought.tsx","type":"registry:file"},{"content":"import {\n  ClipboardCheckIcon,\n  EyeIcon,\n  KeyIcon,\n  LockIcon,\n  SearchIcon,\n  TerminalSquareIcon,\n  UserIcon,\n  XIcon,\n} from \"lucide-react\";\n\nimport { HomeCard, HomeCardDescriptionList } from \"./home-card\";\nimport { SourceIcon } from \"./source-icon\";\n\nexport const FeaturesSection = () => (\n  <div className=\"mt-8 flex flex-col gap-8 lg:flex-row\">\n    <HomeCard\n      title=\"Prebuilt templates\"\n      description={\n        <HomeCardDescriptionList\n          points={[\n            \"Created by top operators\",\n            \"Customize them to fit your needs\",\n            \"Share them with your team\",\n          ]}\n        />\n      }\n      inline\n    >\n      <div className=\"relative h-80 w-full rounded-2xl border border-dashed border-zinc-700\">\n        <SearchIcon className=\"absolute top-4 left-6 h-4 w-4 text-zinc-700\" />\n        <XIcon className=\"absolute top-4 right-6 h-4 w-4 text-zinc-700\" />\n        <p className=\"absolute top-[14px] left-12 text-sm text-zinc-700\">\n          Build a churn analysis dashboard\n        </p>\n        <div className=\"absolute inset-x-4 inset-y-0 z-10 border-x border-dashed border-zinc-700\" />\n        <div className=\"absolute inset-x-0 top-0 h-12 border-b border-dashed border-zinc-700\" />\n        <div className=\"absolute inset-x-0 bottom-0 z-0 flex h-10 flex-row items-center gap-2 overflow-hidden border-t border-dashed border-zinc-700 px-6 text-xs text-zinc-700\">\n          <div className=\"rounded-md border border-dashed border-zinc-700 px-2 py-1 whitespace-nowrap\">\n            Reference 1\n          </div>\n          <div className=\"rounded-md border border-dashed border-zinc-700 px-2 py-1 whitespace-nowrap\">\n            Reference 2\n          </div>\n        </div>\n        <div className=\"absolute inset-x-8 inset-y-16 flex animate-pulse flex-col gap-4\">\n          <div className=\"h-2 w-4/5 rounded bg-zinc-700\" />\n          <div className=\"h-2 w-2/3 rounded bg-zinc-700\" />\n          <div className=\"h-2 w-1/3 rounded bg-zinc-700\" />\n          <div className=\"h-2 w-1/2 rounded bg-zinc-700\" />\n        </div>\n      </div>\n    </HomeCard>\n    <HomeCard\n      className=\"overflow-hidden text-xs\"\n      title=\"Private and secure by default\"\n      description={\n        <HomeCardDescriptionList\n          points={[\n            \"Built in permission and access control\",\n            \"End to end encryption\",\n            \"BYO database, model, or interface\",\n          ]}\n        />\n      }\n      pattern={\n        <div className=\"pointer-events-none absolute top-0 left-0 w-full bg-gradient-to-b from-transparent to-zinc-800 bg-clip-text font-mono text-xs leading-4 tracking-[4px] break-all text-transparent\">\n          0000101001010011011001010110001101110101011100100110100101110100011110010010000001100001011011100110010000100000010100000111001001101001011101100110000101100011011110010000101001010000011100100110100101110110011000010110001101111001001000000110000101101110011001000010000001110011011001010110001101110101011100100110100101110100011110010010000001100001011100100110010100100000011101000110111101101111001000000110100101101101011100000110111101110010011101000110000101101110011101000010000001100110011011110111001000100000011011000110010101100111011000010110110001100101011100110110010100100000010000110110110001100001011110010010000001100100011011110110010101110011001000000110111001101111011101000010000000001010010100110110010101100011011101010111001001101001011101000111100100100000011000010110111001100100001000000101000001110010011010010111011001100001011000110111100100001010010100000111001001101001011101100110000101100011011110010010000001100001011011100110010000100000011100110110010101100011011101010111001001101001011101000111100100100000011000010111001001100101001000000111010001101111011011110010000001101001011011010111000001101111011100100111010001100001011011100111010000100000011001100110111101110010001000000110110001100101011001110110000101101100011001010111001101100101001000000100001101101100011000010111100100100000011001000110111101100101011100110010000001101110011011110111010000100000000010100101001101100101011000110111010101110010011010010111010001111001001000000110000101101110011001000010000001010000011100100110100101110110011000010110001101111001000010100101000001110010011010010111011001100001011000110111100100100000011000010110111001100110111101110010001000000110110001100101011001110110000101101100011001010111001101100101001000000100001101101100011000010111100100100000011001000110111101100101011100110010000001101110011011110111010000100000000010100101001101100101011000110111010101110010011010010111010001111001001000000110000101101110011001000010000001010000011100100110100101110110011000010110001101111001000010100101000001110010011010010111011001100001011000110111100100100000011000010110110100110100101110110011000010110001101111001001000000110000101101101001101001011101100110000101100011011110010010000001100001011011\n        </div>\n      }\n      inline\n    >\n      <div className=\"mt-10 grid w-full grid-cols-3 gap-5\">\n        <div className=\"flex flex-col items-center\">\n          <SourceIcon className=\"rounded\" Icon={KeyIcon} />\n          Secure\n        </div>\n        <div className=\"flex flex-col items-center\">\n          <SourceIcon className=\"rounded\" Icon={LockIcon} />\n          Encrypted\n        </div>\n        <div className=\"flex flex-col items-center\">\n          <SourceIcon className=\"rounded\" Icon={ClipboardCheckIcon} />\n          Compliant\n        </div>\n        <div className=\"flex flex-col items-center\">\n          <SourceIcon className=\"rounded\" Icon={UserIcon} />\n          Access Control\n        </div>\n        <div className=\"flex flex-col items-center\">\n          <SourceIcon className=\"rounded\" Icon={EyeIcon} />\n          Observable\n        </div>\n        <div className=\"flex flex-col items-center\">\n          <SourceIcon className=\"rounded\" Icon={TerminalSquareIcon} />\n          Scriptable\n        </div>\n      </div>\n    </HomeCard>\n  </div>\n);\n","path":"/_components/features-section.tsx","target":"uicapsule/emerald-template/_components/features-section.tsx","type":"registry:file"},{"content":"import type { ComponentType, ReactNode, SVGProps } from \"react\";\nimport { Logo } from \"./logo\";\nimport { WaitlistForm } from \"./waitlist-form\";\n\nconst TwitterIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg viewBox=\"0 0 20 20\" aria-hidden=\"true\" {...props}>\n    <path d=\"M16.712 6.652c.01.146.01.29.01.436 0 4.449-3.267 9.579-9.242 9.579v-.003a8.963 8.963 0 0 1-4.98-1.509 6.379 6.379 0 0 0 4.807-1.396c-1.39-.027-2.608-.966-3.035-2.337.487.097.99.077 1.467-.059-1.514-.316-2.606-1.696-2.606-3.3v-.041c.45.26.956.404 1.475.42C3.18 7.454 2.74 5.486 3.602 3.947c1.65 2.104 4.083 3.382 6.695 3.517a3.446 3.446 0 0 1 .94-3.217 3.172 3.172 0 0 1 4.596.148 6.38 6.38 0 0 0 2.063-.817 3.357 3.357 0 0 1-1.428 1.861 6.283 6.283 0 0 0 1.865-.53 6.735 6.735 0 0 1-1.62 1.744Z\" />\n  </svg>\n);\n\nconst GitHubIcon = (props: SVGProps<SVGSVGElement>) => (\n  <svg viewBox=\"0 0 20 20\" aria-hidden=\"true\" {...props}>\n    <path\n      fillRule=\"evenodd\"\n      clipRule=\"evenodd\"\n      d=\"M10 1.667c-4.605 0-8.334 3.823-8.334 8.544 0 3.78 2.385 6.974 5.698 8.106.417.075.573-.182.573-.406 0-.203-.011-.875-.011-1.592-2.093.397-2.635-.522-2.802-1.002-.094-.246-.5-1.005-.854-1.207-.291-.16-.708-.556-.01-.567.656-.01 1.124.62 1.281.876.75 1.292 1.948.93 2.427.705.073-.555.291-.93.531-1.143-1.854-.213-3.791-.95-3.791-4.218 0-.929.322-1.698.854-2.296-.083-.214-.375-1.09.083-2.265 0 0 .698-.224 2.292.876a7.576 7.576 0 0 1 2.083-.288c.709 0 1.417.096 2.084.288 1.593-1.11 2.291-.875 2.291-.875.459 1.174.167 2.05.084 2.263.53.599.854 1.357.854 2.297 0 3.278-1.948 4.005-3.802 4.219.302.266.563.78.563 1.58 0 1.143-.011 2.061-.011 2.35 0 .224.156.491.573.405a8.365 8.365 0 0 0 4.11-3.116 8.707 8.707 0 0 0 1.567-4.99c0-4.721-3.73-8.545-8.334-8.545Z\"\n    />\n  </svg>\n);\n\nconst SocialLink = ({\n  href,\n  icon: Icon,\n  children,\n}: {\n  href: string;\n  icon: ComponentType<SVGProps<SVGSVGElement>>;\n  children: ReactNode;\n}) => (\n  <a href={href} className=\"group\">\n    <span className=\"sr-only\">{children}</span>\n    <Icon className=\"h-5 w-5 fill-zinc-700 transition group-hover:fill-zinc-900 dark:group-hover:fill-zinc-500\" />\n  </a>\n);\n\nconst SmallPrint = () => (\n  <div className=\"flex flex-col items-center justify-between gap-5 border-t border-white/10 pt-8 sm:flex-row\">\n    <p className=\"text-xs text-zinc-400\">\n      {/* UTC, not local: this tree is prerendered on the server and hydrated in the\n            browser, so a timezone-dependent year mismatches around New Year. */}\n      &copy; Copyright {new Date().getUTCFullYear()}. All rights reserved.\n    </p>\n    <div className=\"flex gap-4\">\n      <SocialLink href=\"\" icon={TwitterIcon}>\n        Follow us on Twitter\n      </SocialLink>\n      <SocialLink href=\"\" icon={GitHubIcon}>\n        Follow us on GitHub\n      </SocialLink>\n    </div>\n  </div>\n);\n\nexport const Footer = () => (\n  <footer className=\"mt-20 border-t border-white/10 text-sm sm:mt-24\">\n    <div className=\"mx-auto max-w-5xl px-5 py-10 md:pt-16 md:pb-12\">\n      <div className=\"flex w-full justify-between pb-10 md:pb-12\">\n        <div className=\"hidden md:block\">\n          <Logo />\n        </div>\n        <div className=\"flex w-full justify-between md:w-auto md:gap-20\">\n          <ul className=\"flex flex-col gap-2\">\n            <p className=\"text-(--muted-foreground)\">Resources</p>\n            <li>\n              <a href=\"/docs\">Documentation</a>\n            </li>\n            <li>\n              <a href=\"/blog\">Blog</a>\n            </li>\n          </ul>\n          <ul className=\"flex flex-col gap-2\">\n            <p className=\"text-(--muted-foreground)\">Company</p>\n            <li>\n              <a href=\"/about\">About</a>\n            </li>\n            <li>\n              <a href=\"/terms\">Terms of Use</a>\n            </li>\n            <li>\n              <a href=\"/privacy\">Privacy Policy</a>\n            </li>\n          </ul>\n          <ul className=\"flex flex-col gap-2\">\n            <p className=\"text-(--muted-foreground)\">Support</p>\n            <li>\n              <a href=\"/help\">Help center</a>\n            </li>\n            <li>\n              <a href=\"/contact\">Contact</a>\n            </li>\n          </ul>\n        </div>\n      </div>\n      <div className=\"flex flex-col justify-between gap-5 border-t border-white/10 py-8 md:flex-row\">\n        <div className=\"w-full md:w-[30%]\">\n          <p>Subscribe to receive our latest updates right to your inbox 🚀</p>\n        </div>\n        <div className=\"flex items-center gap-2 md:ml-auto\">\n          <WaitlistForm />\n        </div>\n      </div>\n      <SmallPrint />\n    </div>\n  </footer>\n);\n","path":"/_components/footer.tsx","target":"uicapsule/emerald-template/_components/footer.tsx","type":"registry:file"},{"content":"import { useId } from \"react\";\nimport type { SVGProps } from \"react\";\n\nexport type GridPatternProps = {\n  width: number;\n  height: number;\n  x?: number | string;\n  y?: number | string;\n  squares?: number[][];\n} & SVGProps<SVGSVGElement>;\n\nexport const GridPattern = ({ width, height, x, y, squares, ...props }: GridPatternProps) => {\n  const patternId = useId();\n\n  return (\n    <svg aria-hidden=\"true\" {...props}>\n      <defs>\n        <pattern\n          id={patternId}\n          width={width}\n          height={height}\n          patternUnits=\"userSpaceOnUse\"\n          x={x}\n          y={y}\n        >\n          <path d={`M.5 ${height}V.5H${width}`} fill=\"none\" />\n        </pattern>\n      </defs>\n      <rect width=\"100%\" height=\"100%\" strokeWidth={0} fill={`url(#${patternId})`} />\n      {squares && (\n        <svg x={x} y={y} className=\"overflow-visible\">\n          {squares.map(([squareX, squareY]) => (\n            <rect\n              strokeWidth=\"0\"\n              key={`${squareX}-${squareY}`}\n              width={width + 1}\n              height={height + 1}\n              x={(squareX ?? 0) * width}\n              y={(squareY ?? 0) * height}\n            />\n          ))}\n        </svg>\n      )}\n    </svg>\n  );\n};\n","path":"/_components/grid-pattern.tsx","target":"uicapsule/emerald-template/_components/grid-pattern.tsx","type":"registry:file"},{"content":"\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { cn } from \"cn\";\nimport { useScroll } from \"motion/react\";\n\nimport { Logo } from \"./logo\";\n\n/** Scroll offset past which the header gains its translucent backdrop. */\nconst BLUR_SCROLL_THRESHOLD = 100;\n\nexport const Header = () => {\n  const [isScrolled, setIsScrolled] = useState(false);\n\n  const { scrollY } = useScroll();\n\n  useEffect(() => {\n    const unsubscribe = scrollY.on(\"change\", (latest) => {\n      setIsScrolled(latest > BLUR_SCROLL_THRESHOLD);\n    });\n    return unsubscribe;\n  }, [scrollY]);\n\n  return (\n    <header\n      className={cn(\"sticky top-0 z-40 w-full bg-transparent\", isScrolled && \"backdrop-blur\")}\n    >\n      <div className=\"mx-auto flex h-16 w-full max-w-5xl items-center justify-between gap-4 px-5\">\n        <div className=\"flex-1\">\n          <a href=\"/\">\n            <Logo />\n          </a>\n        </div>\n        <nav className=\"flex flex-1 justify-center\">\n          <ul className=\"flex gap-3 text-sm md:gap-8\">\n            <li>\n              <a href=\"/\">Home</a>\n            </li>\n            <li>\n              <a href=\"/docs\">Documentation</a>\n            </li>\n          </ul>\n        </nav>\n        <div className=\"flex flex-1 justify-end\">\n          <a\n            className=\"ml-4 inline-flex h-8 w-24 items-center justify-center rounded-full bg-(--secondary) px-5 text-sm font-medium text-(--secondary-foreground) transition-colors hover:bg-(--secondary)/80 focus-visible:ring-2 focus-visible:ring-(--ring)\"\n            href=\"/auth/login\"\n          >\n            Login\n          </a>\n        </div>\n      </div>\n    </header>\n  );\n};\n","path":"/_components/header.tsx","target":"uicapsule/emerald-template/_components/header.tsx","type":"registry:file"},{"content":"\"use client\";\n\nimport { createElement, memo, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ComponentType, SVGProps } from \"react\";\nimport { Badge } from \"./ui\";\nimport { cn } from \"cn\";\nimport {\n  BarChart3,\n  BookOpen,\n  CheckCircle,\n  FileText,\n  GitBranch,\n  Search,\n  Shield,\n  Users,\n} from \"lucide-react\";\nimport {\n  AnimatePresence,\n  motion,\n  useInView,\n  useMotionValueEvent,\n  useScroll,\n  useTransform,\n} from \"motion/react\";\n\nimport {\n  ChainOfThought,\n  ChainOfThoughtContent,\n  ChainOfThoughtHeader,\n  ChainOfThoughtStep,\n} from \"./chain-of-thought\";\n\nconst samples = [\n  {\n    input: \"Can you provide a changelog of everything shipped in Dataembed this week?\",\n    output: {\n      reasoning: [\n        {\n          icon: Search,\n          text: \"Searching through Asana tickets for this week...\",\n        },\n        {\n          icon: GitBranch,\n          text: \"Checking GitHub commits and pull requests...\",\n        },\n        {\n          icon: BarChart3,\n          text: \"Analyzing version releases and deployments...\",\n        },\n        { icon: FileText, text: \"Compiling changelog information...\" },\n      ],\n      references: [\n        { content: \"Ticket #1704\", source: \"asana\" },\n        { content: \"PR #102\", source: \"github\" },\n      ],\n      text: `\nAccording to Asana and Github commits, the following things were completed this week:\n\nVersion 1.1.2 launch - 3/14/2025:\n- Added a new feature for sentiment analysis, allowing users to analyze the sentiment of text inputs\n- Improved the accuracy of the image recognition module by integrating the Azure deep learning model\n- Fixed a bug that caused the application to crash when processing large datasets\n- Optimized the performance of the recommendation engine\n      `.trim(),\n    },\n  },\n  {\n    input: \"Who is responsible for the new landing experience?\",\n    output: {\n      reasoning: [\n        {\n          icon: Users,\n          text: \"Looking up project ownership in team directory...\",\n        },\n        { icon: BookOpen, text: \"Checking project documentation and specs...\" },\n        {\n          icon: Search,\n          text: \"Finding team lead and stakeholder information...\",\n        },\n        { icon: FileText, text: \"Gathering project context and background...\" },\n      ],\n      references: [\n        { content: \"Grow Team\", source: \"site\" },\n        { content: \"Project Neue\", source: \"notion\" },\n        { content: \"Kevin Wu (Grow)\", source: \"person\" },\n      ],\n      text: `\nThe team responsible for \"Project Neue\", the new landing page, is the Grow team. It is an initiative launched by Kevin Wu to showcase our free training and resources programs, to help people acquire the digital skills they need to succeed in the modern economy.\n\nThe initiative aims to bridge the digital skills gap and provide opportunities for individuals and businesses to learn and grow.\n\nThe Grow team collaborates with various partners, including educational institutions, nonprofits, and local communities, to deliver in-person workshops, online training courses, and other resources. \n      `.trim(),\n    },\n  },\n  {\n    input: \"Whats our HR policy on working from home?\",\n    output: {\n      reasoning: [\n        { icon: Search, text: \"Searching HR policy documents...\" },\n        {\n          icon: BookOpen,\n          text: \"Checking employee handbook for remote work...\",\n        },\n        { icon: Shield, text: \"Looking up recent policy updates...\" },\n        { icon: CheckCircle, text: \"Verifying current guidelines...\" },\n      ],\n      references: [\n        { content: \"Onboarding 101\", source: \"ppt\" },\n        { content: \"Patty (HR)\", source: \"person\" },\n      ],\n      text: \"According to the latest onboarding docs, we have a flexible work policy. You can work from home as long as you get your work done and are available for meetings.\",\n    },\n  },\n];\n\nconst wait = (delay: number) => {\n  let timeout: ReturnType<typeof setTimeout>;\n\n  // oxlint-disable-next-line promise/avoid-new -- a cancellable sleep in the browser; there is no promise-returning timer to await here\n  const promise = new Promise((resolve) => {\n    timeout = setTimeout(resolve, delay);\n  });\n\n  return {\n    cancel: () => clearTimeout(timeout),\n    promise,\n  };\n};\n\ntype StepIcon = ComponentType<{ size?: number }>;\n\ntype StepStatus = \"complete\" | \"active\" | \"pending\";\n\nconst stepStatus = (stepIndex: number, currentStepIndex: number): StepStatus => {\n  if (stepIndex < currentStepIndex) {\n    return \"complete\";\n  }\n  if (stepIndex === currentStepIndex) {\n    return \"active\";\n  }\n  return \"pending\";\n};\n\nconst Spinner = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    width=\"16\"\n    height=\"16\"\n    viewBox=\"0 0 24 24\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"currentColor\"\n    {...props}\n  >\n    <path d=\"M2,12A10.94,10.94,0,0,1,5,4.65c-.21-.19-.42-.36-.62-.55h0A11,11,0,0,0,12,23c.34,0,.67,0,1-.05C6,23,2,17.74,2,12Z\">\n      <animateTransform\n        attributeName=\"transform\"\n        type=\"rotate\"\n        dur=\"0.6s\"\n        values=\"0 12 12;360 12 12\"\n        repeatCount=\"indefinite\"\n      />\n    </path>\n  </svg>\n);\n\n// Keyed elements returned directly under AnimatePresence, so the swap between\n// spinner and icon still animates out and in.\nconst statusIcon = (status: StepStatus, staticIcon: StepIcon) => {\n  if (status === \"active\") {\n    return (\n      <motion.div\n        key=\"spinner\"\n        initial={{ opacity: 0, scale: 0.8 }}\n        animate={{ opacity: 1, scale: 1 }}\n        exit={{ opacity: 0, scale: 0.8 }}\n        transition={{\n          duration: 0.2,\n          ease: \"easeOut\",\n        }}\n      >\n        <Spinner />\n      </motion.div>\n    );\n  }\n  if (status === \"complete\") {\n    return (\n      <motion.div\n        key=\"icon\"\n        initial={{ opacity: 0, scale: 0.9 }}\n        animate={{ opacity: 1, scale: 1 }}\n        transition={{\n          duration: 0.3,\n          ease: \"easeOut\",\n        }}\n      >\n        {createElement(staticIcon, { size: 16 })}\n      </motion.div>\n    );\n  }\n  return (\n    <motion.div\n      key=\"pending\"\n      initial={{ opacity: 0.3, scale: 1 }}\n      animate={{ opacity: 0.3, scale: 1 }}\n    >\n      {createElement(staticIcon, { size: 16 })}\n    </motion.div>\n  );\n};\n\nconst AnimatedIconBase = ({\n  stepIndex,\n  staticIcon,\n  currentStepIndex,\n}: {\n  stepIndex: number;\n  staticIcon: StepIcon;\n  currentStepIndex: number;\n}) => (\n  <AnimatePresence mode=\"wait\">\n    {statusIcon(stepStatus(stepIndex, currentStepIndex), staticIcon)}\n  </AnimatePresence>\n);\n\nconst AnimatedIcon = memo(AnimatedIconBase);\n\nconst MemoizedChainOfThoughtStepBase = ({\n  stepIndex,\n  staticIcon,\n  label,\n  currentStepIndex,\n}: {\n  stepIndex: number;\n  staticIcon: StepIcon;\n  label: string;\n  currentStepIndex: number;\n}) => {\n  const status = stepStatus(stepIndex, currentStepIndex);\n\n  return (\n    <ChainOfThoughtStep\n      icon={\n        <AnimatedIcon\n          stepIndex={stepIndex}\n          staticIcon={staticIcon}\n          currentStepIndex={currentStepIndex}\n        />\n      }\n      label={label}\n      status={status}\n    />\n  );\n};\n\nconst MemoizedChainOfThoughtStep = memo(MemoizedChainOfThoughtStepBase);\n\nconst Typewriter = ({\n  start,\n  text,\n  onTyped,\n  splitType = \"letters\",\n  hideCursor,\n}: {\n  start: boolean;\n  text: string;\n  onTyped?: () => void;\n  splitType?: \"letters\" | \"words\";\n  hideCursor?: boolean;\n}) => {\n  const textContainerRef = useRef<HTMLDivElement>(null);\n  const finishedRef = useRef(false);\n\n  useEffect(() => {\n    let i = 0;\n    let timeoutId: ReturnType<typeof setTimeout> | undefined;\n    let cancelled = false;\n    const splitBy = splitType === \"letters\" ? \"\" : \" \";\n    const splitText = text.split(splitBy);\n\n    const write = () => {\n      if (cancelled || !textContainerRef.current || finishedRef.current) {\n        return;\n      }\n      if (i < splitText.length) {\n        textContainerRef.current.textContent = splitText.slice(0, i + 1).join(splitBy);\n        i += 1;\n        timeoutId = setTimeout(write, 25);\n      } else {\n        finishedRef.current = true;\n        i = 0;\n        onTyped?.();\n      }\n    };\n\n    const clear = () => {\n      if (cancelled || !textContainerRef.current || !finishedRef.current) {\n        return;\n      }\n      if (i < splitText.length) {\n        textContainerRef.current.textContent = splitText.slice(0, text.length - i).join(splitBy);\n        i += 1;\n        timeoutId = setTimeout(clear, 5);\n      } else {\n        finishedRef.current = false;\n        i = 0;\n        textContainerRef.current.textContent = \"\";\n      }\n    };\n\n    if (start) {\n      write();\n    } else {\n      clear();\n    }\n\n    return () => {\n      cancelled = true;\n      if (timeoutId !== undefined) {\n        clearTimeout(timeoutId);\n      }\n    };\n  }, [start, text, onTyped, splitType]);\n\n  return (\n    <div>\n      <span ref={textContainerRef} />\n      {!hideCursor && <span className=\"cursor\">|</span>}\n    </div>\n  );\n};\n\nexport const ExampleChat = ({ start }: { start: boolean }) => {\n  const promisesRef = useRef<(() => void)[]>([]);\n  const [currentSampleIndex, setCurrentSampleIndex] = useState(0);\n  const [showQuestion, setShowQuestion] = useState(true);\n  const [showLoading, setShowLoading] = useState(false);\n  const [showChainOfThought, setShowChainOfThought] = useState(false);\n  const [chainOfThoughtOpen, setChainOfThoughtOpen] = useState(true);\n  const [showAnswer, setShowAnswer] = useState(false);\n  const [showFooter, setShowFooter] = useState(false);\n  const [currentStepIndex, setCurrentStepIndex] = useState(-1);\n  const [thinkingDuration, setThinkingDuration] = useState<number | null>(null);\n  const [isThinkingComplete, setIsThinkingComplete] = useState(false);\n\n  const clearAll = useCallback(() => {\n    setShowQuestion(false);\n    setShowLoading(false);\n    setShowChainOfThought(false);\n    setChainOfThoughtOpen(true);\n    setShowAnswer(false);\n    setShowFooter(false);\n    setThinkingDuration(null);\n    setIsThinkingComplete(false);\n  }, []);\n\n  const [previousStart, setPreviousStart] = useState(start);\n  if (previousStart !== start) {\n    setPreviousStart(start);\n    clearAll();\n    setShowQuestion(start);\n  }\n\n  useEffect(() => {\n    if (!start) {\n      return;\n    }\n    const pending = promisesRef.current;\n    return () => {\n      for (const cancel of pending) {\n        cancel();\n      }\n      pending.length = 0;\n    };\n  }, [start]);\n\n  const showResults = async () => {\n    setShowLoading(true);\n    const afterShowLoading = wait(1000);\n    promisesRef.current.push(afterShowLoading.cancel);\n    await afterShowLoading.promise;\n\n    const startTime = Date.now();\n    setShowChainOfThought(true);\n    setChainOfThoughtOpen(true);\n    setCurrentStepIndex(-1);\n    setIsThinkingComplete(false);\n\n    const reasoningStepCount = samples[currentSampleIndex]?.output.reasoning.length ?? 0;\n    for (let i = 0; i < reasoningStepCount; i += 1) {\n      setCurrentStepIndex(i);\n      const stepDelay = wait(800);\n      promisesRef.current.push(stepDelay.cancel);\n      await stepDelay.promise;\n    }\n\n    const afterAllSteps = wait(500);\n    promisesRef.current.push(afterAllSteps.cancel);\n    await afterAllSteps.promise;\n\n    const endTime = Date.now();\n    const duration = Math.round((endTime - startTime) / 1000);\n    setThinkingDuration(duration);\n    setIsThinkingComplete(true);\n\n    setChainOfThoughtOpen(false);\n    const afterCollapse = wait(300);\n    promisesRef.current.push(afterCollapse.cancel);\n    await afterCollapse.promise;\n\n    setShowAnswer(true);\n    const afterShowAnswer = wait(1000);\n    promisesRef.current.push(afterShowAnswer.cancel);\n    await afterShowAnswer.promise;\n\n    setShowFooter(true);\n    const afterShowFooter = wait(5000);\n    promisesRef.current.push(afterShowFooter.cancel);\n    await afterShowFooter.promise;\n\n    clearAll();\n    const afterClearAll = wait(1000);\n    promisesRef.current.push(afterClearAll.cancel);\n    await afterClearAll.promise;\n\n    setCurrentSampleIndex((currentSampleIndex + 1) % samples.length);\n    setShowQuestion(true);\n  };\n\n  const currentSample = samples[currentSampleIndex];\n\n  const chainOfThoughtHeaderText = useMemo(() => {\n    if (isThinkingComplete && thinkingDuration !== null) {\n      return `Thought for ${thinkingDuration} second${thinkingDuration === 1 ? \"\" : \"s\"}`;\n    }\n    return \"Thinking...\";\n  }, [isThinkingComplete, thinkingDuration]);\n\n  const reasoningSteps = useMemo(\n    () =>\n      currentSample?.output.reasoning.map((step, index) => (\n        <MemoizedChainOfThoughtStep\n          key={step.text}\n          stepIndex={index}\n          staticIcon={step.icon}\n          label={step.text}\n          currentStepIndex={currentStepIndex}\n        />\n      )),\n    [currentSample?.output.reasoning, currentStepIndex],\n  );\n\n  return (\n    <section className=\"container shadow-2xl shadow-emerald-900/50\">\n      <section className=\"window\">\n        <div className=\"input\">\n          <Typewriter\n            start={start && showQuestion}\n            text={currentSample?.input ?? \"\"}\n            onTyped={() => showResults()}\n          />\n        </div>\n        <div className={cn(\"loading\", showLoading && \"active\")} />\n        <div className=\"output\">\n          <AnimatePresence>\n            {start && showChainOfThought && (\n              <motion.div\n                className=\"chainOfThought\"\n                initial={{ opacity: 0, y: 20 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: 20 }}\n              >\n                <ChainOfThought open={chainOfThoughtOpen} onOpenChange={setChainOfThoughtOpen}>\n                  <ChainOfThoughtHeader>{chainOfThoughtHeaderText}</ChainOfThoughtHeader>\n                  <ChainOfThoughtContent>{reasoningSteps}</ChainOfThoughtContent>\n                </ChainOfThought>\n              </motion.div>\n            )}\n          </AnimatePresence>\n          <AnimatePresence>\n            {start && showAnswer && (\n              <motion.div\n                className=\"outputText\"\n                initial={{ opacity: 0, y: 20 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: 20 }}\n              >\n                <Typewriter\n                  start\n                  text={currentSample?.output.text ?? \"\"}\n                  splitType=\"words\"\n                  hideCursor\n                />\n              </motion.div>\n            )}\n          </AnimatePresence>\n          <AnimatePresence>\n            {start && showFooter && (\n              <motion.footer\n                className=\"outputFooter\"\n                initial={{ opacity: 0 }}\n                animate={{ opacity: 1 }}\n                exit={{ opacity: 0 }}\n              >\n                <ul className=\"flex gap-2\">\n                  {currentSample?.output.references.map((reference) => (\n                    <Badge key={reference.content}>{reference.content}</Badge>\n                  ))}\n                </ul>\n              </motion.footer>\n            )}\n          </AnimatePresence>\n        </div>\n      </section>\n    </section>\n  );\n};\n\nconst scrollYProgressMap = [0, 0.1];\n\nexport const HeroExample = () => {\n  const [isScaled, setIsScaled] = useState(false);\n  const ref = useRef(null);\n  const isInView = useInView(ref, {\n    amount: 1,\n  });\n  const { scrollYProgress } = useScroll();\n  const y = useTransform(scrollYProgress, scrollYProgressMap, [21.28, 0]);\n  const z = useTransform(scrollYProgress, scrollYProgressMap, [-74.56, 0]);\n  const rotateX = useTransform(scrollYProgress, scrollYProgressMap, [40, 0]);\n  const scale = useTransform(scrollYProgress, scrollYProgressMap, [0.9, 1]);\n\n  useMotionValueEvent(scale, \"change\", (latest) => {\n    if (latest > 0.97) {\n      setIsScaled(true);\n    } else {\n      setIsScaled(false);\n    }\n  });\n\n  const shouldRun = isScaled && isInView;\n\n  return (\n    <>\n      <AnimatePresence>\n        {shouldRun && (\n          <motion.div\n            className=\"pointer-events-none fixed inset-0 bg-transparent backdrop-blur transition\"\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n          />\n        )}\n      </AnimatePresence>\n      <motion.div\n        ref={ref}\n        className=\"mx-auto mt-10 max-w-[900px] px-3 shadow\"\n        style={{\n          rotateX,\n          scale,\n          transformPerspective: 3312,\n          y,\n          z,\n        }}\n      >\n        <ExampleChat start={shouldRun} />\n      </motion.div>\n    </>\n  );\n};\n","path":"/_components/hero-example.tsx","target":"uicapsule/emerald-template/_components/hero-example.tsx","type":"registry:file"},{"content":"import { GridPattern } from \"./grid-pattern\";\nimport { HeroExample } from \"./hero-example\";\n\nconst HeroPattern = () => (\n  <div className=\"absolute inset-0 -z-10 [mask-image:linear-gradient(white,transparent_75%)]\">\n    <GridPattern\n      width={72}\n      height={56}\n      x=\"-12\"\n      y=\"4\"\n      squares={[\n        [4, 3],\n        [2, 1],\n        [7, 3],\n        [10, 6],\n      ]}\n      className=\"h-full w-full fill-white/[0.025] stroke-white/5 mix-blend-overlay\"\n    />\n  </div>\n);\n\nexport const HeroSection = () => (\n  <>\n    <HeroPattern />\n    <section className=\"px-5 pt-[70px] sm:pt-[100px]\">\n      <h1 className=\"mx-auto mt-3 max-w-xl text-3xl font-semibold sm:text-4xl\">\n        <span className=\"block bg-gradient-to-b from-emerald-300 to-green-600 bg-clip-text text-transparent\">\n          Generate software products\n        </span>\n        <span>on your organization data</span>\n      </h1>\n      <p className=\"mx-auto mt-6 max-w-md text-base whitespace-pre-line text-zinc-400\">\n        Everyone on your team should be able to build software to automate their own day to day\n        workflows\n      </p>\n      <div className=\"mt-8 grid items-start justify-center gap-4\">\n        <a className=\"group relative text-xs\" href=\"/\">\n          <div className=\"animate-tilt absolute inset-0 rounded-lg bg-gradient-to-r from-emerald-600 to-teal-600 opacity-75 blur transition group-hover:opacity-100\" />\n          <div className=\"relative flex items-center rounded-full bg-black bg-gradient-to-t from-zinc-900 px-7 py-2.5 text-emerald-400 transition group-hover:text-zinc-100\">\n            Start Building &rarr;\n          </div>\n        </a>\n        <span className=\"text-(--muted-foreground) text-sm\">See samples</span>\n      </div>\n    </section>\n    <div className=\"full-bleed relative\">\n      <video\n        preload=\"metadata\"\n        loop\n        autoPlay\n        muted\n        playsInline\n        className=\"pointer-events-none absolute inset-0 w-full translate-y-10 [mask-image:linear-gradient(transparent_10%,black,transparent)] opacity-50 mix-blend-lighten hue-rotate-[250deg]\"\n      >\n        <source src=\"https://d24l2zb4cwkekfpl.public.blob.vercel-storage.com/emerald-template/home-hero-bg.mov\" />\n      </video>\n      <HeroExample />\n    </div>\n  </>\n);\n","path":"/_components/hero-section.tsx","target":"uicapsule/emerald-template/_components/hero-section.tsx","type":"registry:file"},{"content":"import type { ComponentProps, HTMLAttributes, MouseEvent, ReactNode } from \"react\";\nimport type { MotionValue } from \"motion/react\";\n\nimport { cn } from \"cn\";\nimport { motion, useMotionTemplate, useMotionValue } from \"motion/react\";\n\nimport type { GridPatternProps } from \"./grid-pattern\";\nimport { GridPattern } from \"./grid-pattern\";\n\ntype CardGridProps = Omit<GridPatternProps, \"width\" | \"height\">;\n\nconst Pattern = ({\n  mouseX,\n  mouseY,\n  ...gridProps\n}: CardGridProps & {\n  mouseX: MotionValue<number>;\n  mouseY: MotionValue<number>;\n}) => {\n  const maskImage = useMotionTemplate`radial-gradient(1000px at ${mouseX}px ${mouseY}px, rgba(255,255,255,.5), transparent 40%)`;\n  const style = { WebkitMaskImage: maskImage, maskImage };\n\n  return (\n    <div className=\"pointer-events-none\">\n      <div className=\"absolute inset-0 rounded-2xl [mask-image:linear-gradient(white,transparent)] transition duration-300 group-hover:opacity-50\">\n        <GridPattern\n          width={72}\n          height={56}\n          x=\"50%\"\n          className=\"absolute inset-x-0 inset-y-[-30%] h-[160%] w-full fill-white/[0.025] stroke-white/5\"\n          {...gridProps}\n        />\n      </div>\n      <motion.div\n        className=\"absolute inset-0 rounded-2xl bg-gradient-to-r from-[#202e26] to-[#28342e] opacity-0 transition duration-300 group-hover:opacity-100\"\n        style={style}\n      />\n      <motion.div\n        className=\"absolute inset-0 rounded-2xl opacity-0 mix-blend-overlay transition duration-300 group-hover:opacity-100\"\n        style={style}\n      >\n        <GridPattern\n          width={72}\n          height={56}\n          x=\"50%\"\n          className=\"absolute inset-x-0 inset-y-[-30%] h-[160%] w-full fill-white/[0.025] stroke-white/10\"\n          {...gridProps}\n        />\n      </motion.div>\n    </div>\n  );\n};\n\nconst Card = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n  <div\n    data-slot=\"card\"\n    className={cn(\"bg-(--card) flex flex-col gap-3 overflow-hidden border p-3\", className)}\n    {...props}\n  />\n);\n\nexport const HighlightCard = ({\n  className,\n  gridProps,\n  children,\n  pattern = null,\n  ...props\n}: {\n  className?: string;\n  gridProps?: CardGridProps;\n  pattern?: ReactNode;\n  children?: ReactNode;\n} & ComponentProps<typeof Card>) => {\n  const mouseX = useMotionValue(0);\n  const mouseY = useMotionValue(0);\n\n  const onMouseMove = ({ currentTarget, clientX, clientY }: MouseEvent) => {\n    const { left, top } = currentTarget.getBoundingClientRect();\n    mouseX.set(clientX - left);\n    mouseY.set(clientY - top);\n  };\n\n  return (\n    <Card\n      className={cn(\"group shadow-highlight relative rounded-2xl bg-zinc-900/90\", className)}\n      onMouseMove={onMouseMove}\n      {...props}\n    >\n      {pattern}\n      <Pattern {...gridProps} mouseX={mouseX} mouseY={mouseY} />\n      <div className=\"absolute inset-0 rounded-2xl ring-1 ring-white/0 ring-inset group-hover:ring-white/5\" />\n      <div className=\"relative h-full\">{children}</div>\n    </Card>\n  );\n};\n","path":"/_components/highlight-card.tsx","target":"uicapsule/emerald-template/_components/highlight-card.tsx","type":"registry:file"},{"content":"import type { ReactNode } from \"react\";\nimport { cn } from \"cn\";\n\nimport { HighlightCard } from \"./highlight-card\";\n\nconst cardGridProps = {\n  squares: [\n    [-1, 2],\n    [1, 3],\n  ],\n  y: -6,\n};\n\nexport const HomeCard = ({\n  className,\n  title,\n  description,\n  inline,\n  pattern,\n  children,\n}: {\n  className?: string;\n  title?: ReactNode;\n  description?: ReactNode;\n  inline?: boolean;\n  pattern?: ReactNode;\n  children?: ReactNode;\n}) => (\n  <HighlightCard className={cn(\"grow\", className)} pattern={pattern} gridProps={cardGridProps}>\n    <div\n      className={cn(\n        \"flex h-full items-center gap-5 text-center lg:gap-8 lg:text-start\",\n        inline ? \"flex-col\" : \"flex-col lg:flex-row\",\n      )}\n    >\n      <div className=\"flex min-w-[300px] shrink-0 flex-col gap-2 lg:gap-5\">\n        <h3 className=\"text-xl font-semibold sm:text-2xl\">{title}</h3>\n        <div className=\"text-start text-sm text-zinc-300 sm:text-base\">{description}</div>\n      </div>\n      {children}\n    </div>\n  </HighlightCard>\n);\n\nexport const HomeCardDescriptionList = ({ points }: { points: string[] }) => (\n  <ul className=\"flex flex-col gap-1\">\n    {points.map((point) => (\n      <li className=\"flex items-start gap-2.5\" key={point}>\n        <svg\n          className=\"mt-1.5 h-4 w-4 flex-none text-green-500\"\n          fill=\"none\"\n          viewBox=\"0 0 24 24\"\n          stroke=\"currentColor\"\n        >\n          <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M5 13l4 4L19 7\" />\n        </svg>\n        {point}\n      </li>\n    ))}\n  </ul>\n);\n","path":"/_components/home-card.tsx","target":"uicapsule/emerald-template/_components/home-card.tsx","type":"registry:file"},{"content":"import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"cn\";\n\nexport const InfiniteLooper = ({\n  speed = 70,\n  direction = \"right\",\n  children,\n  className,\n  containerClassName,\n}: {\n  speed?: number;\n  direction?: \"right\" | \"left\";\n  children: ReactNode;\n  className?: string;\n  containerClassName?: string;\n}) => {\n  const [animating, setAnimating] = useState(true);\n  const [looperInstances, setLooperInstances] = useState(1);\n  const outerRef = useRef<HTMLDivElement>(null);\n  const innerRef = useRef<HTMLDivElement>(null);\n\n  const restartTimeoutRef = useRef(0);\n\n  const setupInstances = useCallback(() => {\n    const inner = innerRef.current;\n    const outer = outerRef.current;\n    if (!inner || !outer) {\n      return;\n    }\n\n    const { width } = inner.getBoundingClientRect();\n    const { width: parentWidth } = outer.getBoundingClientRect();\n\n    const widthDeficit = parentWidth - width;\n    const instanceWidth = width / inner.children.length;\n\n    if (widthDeficit) {\n      setLooperInstances(looperInstances + Math.ceil(widthDeficit / instanceWidth) + 1);\n    }\n\n    // Drop and re-add the animation class so every instance restarts in phase.\n    setAnimating(false);\n    window.clearTimeout(restartTimeoutRef.current);\n    restartTimeoutRef.current = window.setTimeout(() => setAnimating(true), 10);\n  }, [looperInstances]);\n\n  useEffect(() => {\n    setupInstances();\n    window.addEventListener(\"resize\", setupInstances);\n\n    return () => {\n      window.removeEventListener(\"resize\", setupInstances);\n      window.clearTimeout(restartTimeoutRef.current);\n    };\n  }, [setupInstances]);\n\n  return (\n    <div className={cn(\"w-full overflow-hidden\", containerClassName)} ref={outerRef}>\n      <div className={cn(\"flex w-fit justify-center\", className)} ref={innerRef}>\n        {Array.from({ length: looperInstances }, (_, index) => (\n          <div\n            key={index}\n            className={cn(\"flex w-max\", animating && \"animate-slide-across\")}\n            style={{\n              animationDirection: direction === \"right\" ? \"reverse\" : \"normal\",\n              animationDuration: `${speed}s`,\n            }}\n          >\n            {children}\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n};\n","path":"/_components/infinite-loop.tsx","target":"uicapsule/emerald-template/_components/infinite-loop.tsx","type":"registry:file"},{"content":"import type { ReactNode } from \"react\";\n\nimport { HomeCard, HomeCardDescriptionList } from \"./home-card\";\nimport { InfiniteLooper } from \"./infinite-loop\";\n\nconst QuestionCard = ({ children }: { children: ReactNode }) => (\n  <div className=\"mr-3 rounded border border-dashed border-zinc-700 bg-zinc-900 p-3 text-xs text-white\">\n    {children}\n  </div>\n);\n\nexport const IntegrationsSection = () => (\n  <HomeCard\n    className=\"mt-8 lg:pl-10\"\n    title=\"We'll go where you go\"\n    description={\n      <HomeCardDescriptionList\n        points={[\n          \"Direct data integrations with the tools you already use\",\n          \"Multi-platform to work where you work\",\n        ]}\n      />\n    }\n  >\n    <div className=\"w-full overflow-hidden\">\n      <h3 className=\"text-center text-xs\">Things people have asked:</h3>\n      <InfiniteLooper containerClassName=\"mt-3\">\n        <QuestionCard>When does the next fundraise start?</QuestionCard>\n        <QuestionCard>Whats the latest on the Block deal?</QuestionCard>\n        <QuestionCard>Who is managing design system project?</QuestionCard>\n      </InfiniteLooper>\n      <InfiniteLooper containerClassName=\"mt-3\" speed={120} direction=\"left\">\n        <QuestionCard>Can you summarize the last all hands?</QuestionCard>\n        <QuestionCard>Whats does the Grow team do?</QuestionCard>\n        <QuestionCard>\n          Can you provide a changelog of everything shipped in TC this week?\n        </QuestionCard>\n        <QuestionCard>Whats our HR policy on working from home?</QuestionCard>\n      </InfiniteLooper>\n      <InfiniteLooper containerClassName=\"mt-3\" speed={30}>\n        <QuestionCard>Who do I contact to get Airtable access?</QuestionCard>\n        <QuestionCard>Who is responsible for the design of the landing experience?</QuestionCard>\n      </InfiniteLooper>\n    </div>\n  </HomeCard>\n);\n","path":"/_components/integrations-section.tsx","target":"uicapsule/emerald-template/_components/integrations-section.tsx","type":"registry:file"},{"content":"import type { SVGProps } from \"react\";\n\nexport const Logo = (props: SVGProps<SVGSVGElement>) => (\n  <svg\n    width=\"32\"\n    height=\"32\"\n    viewBox=\"0 0 606.59 688\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"currentColor\"\n    {...props}\n  >\n    <path\n      fillRule=\"evenodd\"\n      strokeWidth=\"5\"\n      d=\"M518.854155,773.039047 C494.000914,731.902161 470.162892,638.706311 470.162892,511.967229 C470.162892,492.317684 470.761134,473.527799 471.821153,455.554864 C460.599977,449.907842 449.739952,444.739556 439.333432,440.105112 C437.601425,463.725069 436.719913,487.867158 436.719913,511.967229 C436.719913,613.964251 452.35347,716.703142 482.677044,776.748393 L301.522693,672.215101 C335.315795,672.183415 425.688272,619.850986 424.56071,608.209771 C359.762397,634.44108 309.926341,642.523803 283.450678,637.214995 C279.411854,632.058419 274.132436,627.913044 268.035604,625.280339 L268.035604,398.664452 C274.148977,396.008326 279.444248,391.852619 283.488585,386.674 C323.980208,378.611942 419.003536,401.80758 538.365948,473.081437 C554.307586,482.602436 569.298101,492.218493 583.433985,501.815952 C593.531045,494.765095 603.049161,487.779677 611.995225,480.903783 C593.786056,468.197638 574.846315,455.934409 555.520611,444.392386 C457.484017,385.858426 362.711565,351.793751 301.526828,351.716602 L482.656367,247.194332 C466.743676,278.735137 468.224119,379.776753 478.996614,384.801762 C488.149443,322.820213 503.291587,276.667271 518.833478,250.903678 C525.263892,250.002 531.198069,247.563544 536.250045,243.952012 L732.82912,357.385667 C732.753306,358.376204 732.677492,359.35503 732.677492,360.366232 L732.677492,362.422387 C732.677492,366.785432 733.414956,370.974892 734.724472,374.902596 C714.123713,416.810971 647.035125,485.952902 538.365948,550.851644 C521.445619,560.958147 505.035312,570.065159 489.183272,578.27876 C490.065472,590.791344 491.168223,602.726001 492.470847,614.084107 C513.126744,603.781976 534.25131,592.248907 555.520611,579.540695 C642.134777,527.818569 721.7258,461.756395 756.496904,404.995482 L756.496904,619.02508 C737.743252,588.396974 648.971831,536.869786 639.701834,543.692641 C689.566836,584.535397 721.581064,622.375546 734.683119,649.140008 C733.401172,653.03396 732.677492,657.191734 732.677492,661.521026 L732.677492,663.577182 C732.677492,664.578051 732.753306,665.56721 732.82912,666.557746 L536.250045,779.990712 C531.204961,776.37918 525.284569,773.942791 518.854155,773.039047 Z M813.589783,363.027807 L813.589783,360.972712 C813.589783,339.170804 795.931864,321.499052 774.162014,321.499052 L772.106049,321.499052 C763.559011,321.499052 755.665206,324.250883 749.208513,328.882936 L553.087335,215.508471 C553.162973,214.519822 553.23861,213.529108 553.23861,212.528755 L553.23861,210.47366 C553.23861,188.670375 535.587567,171 513.817717,171 L511.761752,171 C489.991902,171 472.340171,188.670375 472.340171,210.47366 L472.340171,212.528755 C472.340171,213.529108 472.416496,214.519822 472.492134,215.508471 L276.370956,328.882936 C269.90945,324.250883 262.023209,321.499052 253.475483,321.499052 L251.423644,321.499052 C229.648293,321.499052 212,339.170804 212,360.972712 L212,363.027807 C212,379.253075 221.78543,393.171955 235.763242,399.251181 L235.763242,625.750196 C221.78543,631.817718 212,645.746925 212,661.972193 L212,664.027288 C212,685.818869 229.648293,703.500948 251.423644,703.500948 L253.475483,703.500948 C262.023209,703.500948 269.90945,700.749117 276.370956,696.117064 L472.492134,809.491529 C472.416496,810.471228 472.340171,811.459876 472.340171,812.471245 L472.340171,814.525651 C472.340171,836.317921 489.991902,854 511.761752,854 L513.817717,854 C535.587567,854 553.23861,836.317921 553.23861,814.525651 L553.23861,812.471245 C553.23861,811.459876 553.162973,810.471228 553.087335,809.491529 L749.208513,696.117064 C755.665206,700.749117 763.559011,703.500948 772.106049,703.500948 L774.162014,703.500948 C795.931864,703.500948 813.589783,685.818869 813.589783,664.027288 L813.589783,661.972193 C813.589783,645.746925 803.798164,631.817718 789.812102,625.750196 L789.812102,399.251181 C803.798164,393.182282 813.589783,379.253075 813.589783,363.027807 L813.589783,363.027807 Z\"\n      transform=\"translate(-209.5 -168.5)\"\n    />\n  </svg>\n);\n","path":"/_components/logo.tsx","target":"uicapsule/emerald-template/_components/logo.tsx","type":"registry:file"},{"content":"import type { ComponentType, SVGProps } from \"react\";\nimport { cn } from \"cn\";\n\nconst ICON_ASSET_BASE = \"https://d24l2zb4cwkekfpl.public.blob.vercel-storage.com/emerald-template\";\n\nconst shellClassName =\n  \"inline-flex justify-center rounded-full border border-dashed border-zinc-700 bg-zinc-900 p-3 text-white\";\n\n/** An icon rendered from a component (lucide / simple-icons). */\nexport const SourceIcon = ({\n  Icon,\n  className,\n}: {\n  Icon: ComponentType<SVGProps<SVGSVGElement>>;\n  className?: string;\n}) => (\n  <div className={cn(shellClassName, className)}>\n    <Icon className=\"size-5\" />\n  </div>\n);\n\n/** An icon rendered from a remotely hosted brand SVG, addressed by id. */\nexport const SourceAssetIcon = ({ id, className }: { id: string; className?: string }) => (\n  <div className={cn(shellClassName, className)}>\n    <img alt={id} width={20} height={20} className=\"size-5\" src={`${ICON_ASSET_BASE}/${id}.svg`} />\n  </div>\n);\n","path":"/_components/source-icon.tsx","target":"uicapsule/emerald-template/_components/source-icon.tsx","type":"registry:file"},{"content":"import type { ComponentProps } from \"react\";\nimport { cn } from \"cn\";\n\nexport const Button = ({ className, ...props }: ComponentProps<\"button\">) => (\n  <button\n    type=\"button\"\n    className={cn(\n      \"inline-flex h-9 items-center justify-center gap-2 rounded-full px-4 py-2 text-sm font-medium outline-none transition-colors hover:bg-(--muted) focus-visible:ring-2 focus-visible:ring-(--ring) disabled:opacity-50\",\n      className,\n    )}\n    {...props}\n  />\n);\n\nexport const Badge = ({ className, ...props }: ComponentProps<\"span\">) => (\n  <span\n    className={cn(\n      \"inline-flex items-center rounded-full bg-(--primary) px-2 py-0.5 text-xs font-medium text-(--primary-foreground)\",\n      className,\n    )}\n    {...props}\n  />\n);\n","path":"/_components/ui.tsx","target":"uicapsule/emerald-template/_components/ui.tsx","type":"registry:file"},{"content":"\"use client\";\n\nimport { useState } from \"react\";\nimport type { FormEvent } from \"react\";\nimport { Button } from \"./ui\";\n\nexport const WaitlistForm = () => {\n  const [email, setEmail] = useState(\"\");\n  const [submitted, setSubmitted] = useState(false);\n\n  const handleJoinWaitlist = (event: FormEvent<HTMLFormElement>) => {\n    event.preventDefault();\n    if (!email) {\n      return;\n    }\n    setSubmitted(true);\n    setEmail(\"\");\n  };\n\n  return (\n    <form\n      className=\"border-(--border) relative flex max-w-sm items-center gap-2 rounded-full border shadow-lg\"\n      onSubmit={handleJoinWaitlist}\n    >\n      <label htmlFor=\"waitlist-email\" className=\"sr-only\">\n        Email\n      </label>\n      <input\n        id=\"waitlist-email\"\n        className=\"w-full min-w-0 flex-1 border-none bg-transparent py-2 pl-4 text-sm placeholder-white/50 focus:placeholder-white/75 focus:ring-0 focus:outline-hidden\"\n        required\n        type=\"email\"\n        placeholder=\"name@example.com\"\n        autoCapitalize=\"none\"\n        autoComplete=\"email\"\n        autoCorrect=\"off\"\n        value={email}\n        onChange={(event) => {\n          setEmail(event.target.value);\n          setSubmitted(false);\n        }}\n      />\n      <Button type=\"submit\" className=\"text-xs hover:bg-transparent\">\n        Join Waitlist\n      </Button>\n      <output className=\"absolute top-full left-4 mt-2 text-xs text-emerald-400\">\n        {submitted ? \"Waitlist joined!\" : \"\"}\n      </output>\n    </form>\n  );\n};\n","path":"/_components/waitlist-form.tsx","target":"uicapsule/emerald-template/_components/waitlist-form.tsx","type":"registry:file"},{"content":"import { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"cn\";\nimport { SiGithub } from \"@icons-pack/react-simple-icons\";\nimport {\n  ApertureIcon,\n  AppWindowIcon,\n  BracesIcon,\n  DatabaseIcon,\n  FileSpreadsheetIcon,\n  GlobeIcon,\n  UploadIcon,\n} from \"lucide-react\";\nimport { motion } from \"motion/react\";\n\nimport { HomeCard } from \"./home-card\";\nimport { Logo } from \"./logo\";\nimport { SourceAssetIcon, SourceIcon } from \"./source-icon\";\n\n/** How far the source/output diagram slides up as each workflow step is highlighted. */\nconst stepTranslateY = [0, -100, -170];\n\nconst workflowSteps = [\"Connect your data source\", \"Build your app\", \"One click deploy\"];\n\nconst Lines = ({\n  className,\n  width,\n  height,\n  radius,\n  strokeWidth,\n  highlightStrokeWidth,\n  strokeDasharray,\n  invert,\n}: {\n  className?: string;\n  width: number;\n  height: number;\n  radius: number;\n  strokeWidth: number;\n  highlightStrokeWidth: number;\n  strokeDasharray: number;\n  invert?: boolean;\n}) => {\n  const topLinesHeight = Math.round(height / 3);\n  const bottomLineHeight = height - topLinesHeight;\n  const thirdWidth = Math.round(width / 3);\n  const halfWidth = Math.round(width / 2);\n  const sixthWidth = Math.round(width / 6);\n\n  const path = `M1 0v${\n    topLinesHeight - radius\n  }a${radius} ${radius} 0 00${radius} ${radius}h${halfWidth - radius}M${\n    width - 1\n  } 0v${topLinesHeight - radius}a${radius} ${radius} 0 01-${radius} ${radius}H${\n    halfWidth + 1\n  }v${bottomLineHeight}m-${sixthWidth} -${height}v${topLinesHeight}m${thirdWidth} -${topLinesHeight}v${topLinesHeight}`;\n\n  const animate = invert\n    ? {\n        x1: [0, 0],\n        x2: [0, 0],\n        y1: [2.5 * height, -2 * height],\n        y2: [2 * height, -2.5 * height],\n      }\n    : {\n        x1: [0, 0],\n        x2: [0, 0],\n        y1: [-2.5 * height, 2 * height],\n        y2: [-2 * height, 2.5 * height],\n      };\n\n  const animateId = `pulse-${invert ? \"inverted\" : \"normal\"}`;\n\n  return (\n    <svg\n      className={cn(invert && \"rotate-180\", className)}\n      viewBox={`0 0 ${width} ${height}`}\n      fill=\"none\"\n    >\n      <path\n        d={path}\n        stroke=\"#ffffff20\"\n        strokeDasharray={strokeDasharray}\n        strokeWidth={strokeWidth}\n      />\n      <path\n        d={path}\n        stroke={`url(#${animateId})`}\n        strokeLinecap=\"round\"\n        strokeWidth={highlightStrokeWidth}\n        strokeDasharray={strokeDasharray}\n      />\n      <defs>\n        <motion.linearGradient\n          animate={animate}\n          transition={{\n            duration: 2,\n            repeat: Infinity,\n          }}\n          id={animateId}\n          gradientUnits=\"userSpaceOnUse\"\n        >\n          <stop stopColor=\"oklch(0.696 0.17 162.48)\" stopOpacity=\"0\" />\n          <stop stopColor=\"oklch(0.696 0.17 162.48)\" stopOpacity=\"0.4\" />\n          <stop offset=\"1\" stopColor=\"oklch(0.696 0.17 162.48)\" stopOpacity=\"0\" />\n        </motion.linearGradient>\n      </defs>\n    </svg>\n  );\n};\n\nexport const WorkflowSection = () => {\n  const [highlighted, setHighlighted] = useState(0);\n  const sourcesContainerRef = useRef<HTMLDivElement>(null);\n  const [sourcesContainerWidth, setSourcesContainerWidth] = useState(0);\n\n  useEffect(() => {\n    const container = sourcesContainerRef.current;\n    if (!container) {\n      return;\n    }\n\n    const observer = new ResizeObserver(() => {\n      setSourcesContainerWidth(container.getBoundingClientRect().width);\n    });\n    observer.observe(container);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, []);\n\n  return (\n    <section className=\"px-5 pt-20 sm:pt-24\">\n      <h2 className=\"mx-auto mt-3 max-w-xl text-3xl font-semibold sm:text-4xl\">\n        Simple prompt based workflow\n      </h2>\n      <HomeCard\n        className=\"mt-14 lg:pl-10\"\n        title=\"Plug 'n Play\"\n        description={\n          <ol className=\"ml-5 flex list-decimal flex-col gap-1\">\n            {workflowSteps.map((item, index) => (\n              // oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- hover only previews the step's sources; nothing is actioned, so there is no keyboard equivalent to provide\n              <li\n                className=\"relative leading-9\"\n                onMouseEnter={() => setHighlighted(index)}\n                key={item}\n              >\n                {highlighted === index && (\n                  <motion.div\n                    layoutId=\"about-card-active\"\n                    className=\"pointer-events-none absolute top-0 -left-7 h-full w-full rounded bg-black/50\"\n                  />\n                )}\n                <span className=\"relative\">{item}</span>\n              </li>\n            ))}\n          </ol>\n        }\n      >\n        <div className=\"flex grow items-center justify-center overflow-hidden\">\n          <div\n            className=\"max-h-[254px] transition duration-500 ease-in-out\"\n            style={{ transform: `translateY(${stepTranslateY[highlighted] ?? 0}px)` }}\n          >\n            <div className=\"grid grid-cols-4 items-center justify-center gap-4\">\n              <SourceIcon Icon={DatabaseIcon} />\n              <SourceIcon Icon={FileSpreadsheetIcon} />\n              <SourceAssetIcon id=\"drive\" />\n              <SourceAssetIcon id=\"linear\" />\n              <SourceIcon Icon={GlobeIcon} />\n              <SourceIcon Icon={SiGithub} />\n              <SourceAssetIcon id=\"markdown\" />\n              <SourceIcon Icon={UploadIcon} />\n            </div>\n            <div className=\"w-full px-5\">\n              <div ref={sourcesContainerRef}>\n                <Lines\n                  width={sourcesContainerWidth}\n                  height={100}\n                  radius={5}\n                  strokeWidth={1}\n                  highlightStrokeWidth={2}\n                  strokeDasharray={2}\n                />\n              </div>\n              <div className=\"flex justify-center\">\n                <div className=\"shadow-highlight rounded-full p-3 text-white\">\n                  <Logo className=\"size-5\" />\n                </div>\n              </div>\n              <Lines\n                width={sourcesContainerWidth}\n                height={100}\n                radius={5}\n                strokeWidth={1}\n                highlightStrokeWidth={2}\n                strokeDasharray={2}\n                invert\n              />\n            </div>\n            <div className=\"grid grid-cols-4 items-center justify-center gap-4\">\n              <SourceIcon Icon={AppWindowIcon} />\n              <SourceIcon Icon={BracesIcon} />\n              <SourceAssetIcon id=\"slack\" />\n              <SourceIcon Icon={ApertureIcon} />\n            </div>\n          </div>\n        </div>\n      </HomeCard>\n    </section>\n  );\n};\n","path":"/_components/workflow-section.tsx","target":"uicapsule/emerald-template/_components/workflow-section.tsx","type":"registry:file"},{"content":".emerald-template {\n  --background: hsl(240 10% 3.9%);\n  --foreground: hsl(0 0% 98%);\n  --card: hsl(240 10% 3.9%);\n  --card-foreground: hsl(0 0% 98%);\n  --popover: hsl(240 10% 3.9%);\n  --popover-foreground: hsl(0 0% 98%);\n  --primary: hsl(0 0% 98%);\n  --primary-foreground: hsl(240 5.9% 10%);\n  --secondary: hsl(240 3.7% 15.9%);\n  --secondary-foreground: hsl(0 0% 98%);\n  --muted: hsl(240 3.7% 15.9%);\n  --muted-foreground: hsl(240 5% 64.9%);\n  --accent: hsl(240 3.7% 15.9%);\n  --accent-foreground: hsl(0 0% 98%);\n  --destructive: hsl(0 62.8% 30.6%);\n  --destructive-foreground: hsl(0 0% 98%);\n  --border: hsl(240 3.7% 15.9%);\n  --input: hsl(240 3.7% 15.9%);\n  --ring: hsl(240 4.9% 83.9%);\n  --radius: 0.3rem;\n  background: var(--background);\n  color: var(--foreground);\n}\n\n.emerald-template .contained-page {\n  --viewport-padding: 16px;\n\n  display: grid;\n  grid-template-columns:\n    1fr\n    min(1024px, calc(100% - var(--viewport-padding) * 2))\n    1fr;\n  gap: 0 var(--viewport-padding);\n}\n\n.emerald-template .contained-page > * {\n  grid-column: 2;\n}\n\n.emerald-template .full-bleed {\n  width: 100%;\n  grid-column: 1 / 4;\n}\n\n@keyframes emerald-tilt {\n  0%,\n  50%,\n  100% {\n    transform: rotate(0deg);\n  }\n  25% {\n    transform: rotate(2deg);\n  }\n  75% {\n    transform: rotate(-2deg);\n  }\n}\n\n@keyframes emerald-disco {\n  from {\n    transform: translateY(-50%) rotate(0deg);\n  }\n  to {\n    transform: translateY(-50%) rotate(360deg);\n  }\n}\n\n@keyframes emerald-slide-across {\n  from {\n    transform: translateX(0);\n  }\n  to {\n    transform: translateX(-100%);\n  }\n}\n\n.emerald-template .animate-tilt {\n  animation: emerald-tilt 6s linear infinite;\n}\n\n.emerald-template .animate-disco {\n  animation: emerald-disco 6s linear infinite;\n}\n\n.emerald-template .animate-slide-across {\n  animation: emerald-slide-across linear infinite;\n}\n\n.emerald-template .container {\n  --border-radius: 12px;\n  --height: 400px;\n\n  text-align: start;\n  position: relative;\n}\n\n.emerald-template .container::before {\n  position: absolute;\n  top: -1px;\n  left: -1px;\n  z-index: -1;\n  width: calc(100% + 2px);\n  height: calc(100% + 2px);\n  background: linear-gradient(hsla(0, 0%, 100%, 0.1), transparent);\n  border-radius: var(--border-radius);\n  content: \"\";\n}\n\n.emerald-template .window {\n  position: relative;\n  width: 100%;\n  overflow: hidden;\n  background: linear-gradient(hsla(0, 0%, 100%, 0.06), transparent), #000;\n  border-radius: var(--border-radius);\n}\n\n.emerald-template .input {\n  position: relative;\n  z-index: 1;\n  display: flex;\n  align-items: center;\n  height: 86px;\n  padding: 0 32px;\n  color: #fff;\n  background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.75));\n}\n\n.emerald-template .input::before {\n  position: absolute;\n  top: -10px;\n  left: 10%;\n  z-index: -1;\n  width: 80%;\n  height: 20px;\n  background-color: #16413d;\n  border-radius: 50%;\n  filter: blur(40px);\n  content: \"\";\n}\n\n.emerald-template .loading {\n  position: relative;\n  width: 100%;\n  height: 1px;\n  background: linear-gradient(hsla(0, 0%, 100%, 0.25), hsla(0, 0%, 100%, 0.05));\n}\n\n.emerald-template .loading::before,\n.emerald-template .loading::after {\n  position: absolute;\n  top: 0;\n  left: 0;\n  width: 100%;\n  background: linear-gradient(\n    90deg,\n    rgba(144, 224, 196, 0),\n    rgba(162, 183, 231, 0.5) 41%,\n    #059669 91%,\n    #6ee7b7 122%\n  );\n  transform-origin: 0 50%;\n  opacity: 0;\n  content: \"\";\n}\n\n.emerald-template .loading::before {\n  height: 4px;\n  filter: blur(4px) saturate(1.5);\n}\n\n.emerald-template .loading::after {\n  height: 1px;\n}\n\n.emerald-template .loading.active::before,\n.emerald-template .loading.active::after {\n  animation-name: emerald-loading;\n  animation-duration: 1.4s;\n  animation-timing-function: ease-in-out;\n  animation-fill-mode: forwards;\n}\n\n@keyframes emerald-loading {\n  0% {\n    transform: scaleX(0) translateX(-50%);\n    opacity: 1;\n  }\n  100% {\n    transform: scaleX(1) translateX(100%);\n  }\n}\n\n.emerald-template .output {\n  height: var(--height);\n  padding: 24px 32px;\n}\n\n.emerald-template .outputText {\n  min-height: calc(100% - 32px);\n  max-height: calc(100% - 32px);\n  overflow: hidden;\n  -webkit-mask-image: linear-gradient(0deg, transparent 0, #000 20%);\n  mask-image: linear-gradient(0deg, transparent 0, #000 20%);\n  white-space: pre-wrap;\n}\n\n.emerald-template .outputFooter {\n  position: absolute;\n  right: 32px;\n  bottom: 24px;\n  left: 32px;\n  display: flex;\n  justify-content: space-between;\n}\n\n.emerald-template .cursor {\n  animation: emerald-cursor 1s infinite;\n  margin-left: 1px;\n}\n\n@keyframes emerald-cursor {\n  0% {\n    opacity: 0;\n  }\n  50% {\n    opacity: 1;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n\n@layer base {\n  :where(.emerald-template, .emerald-template *) {\n    border-color: var(--border);\n  }\n}\n","path":"/preview.css","target":"uicapsule/emerald-template/preview.css","type":"registry:file"},{"content":"\"use client\";\n\nimport { FeaturesSection } from \"./_components/features-section\";\nimport { Footer } from \"./_components/footer\";\nimport { Header } from \"./_components/header\";\nimport { HeroSection } from \"./_components/hero-section\";\nimport { IntegrationsSection } from \"./_components/integrations-section\";\nimport { WorkflowSection } from \"./_components/workflow-section\";\n\nimport \"./preview.css\";\n\nconst Preview = () => (\n  <div className=\"emerald-template font-sans antialiased\">\n    <Header />\n    <main className=\"contained-page text-center\">\n      <HeroSection />\n      <WorkflowSection />\n      <FeaturesSection />\n      <IntegrationsSection />\n    </main>\n    <Footer />\n  </div>\n);\n\nexport default Preview;\n","path":"/preview.tsx","target":"uicapsule/emerald-template/preview.tsx","type":"registry:file"},{"content":"declare module \"*.css\" {}\n","path":"/styles.d.ts","target":"uicapsule/emerald-template/styles.d.ts","type":"registry:file"}],"homepage":"https://www.uicapsule.com/ui/emerald-template","name":"emerald-template","registryDependencies":[],"title":"Emerald","type":"registry:block"}