{
  "name": "team-cluster-01-default",
  "type": "registry:block",
  "tier": "free",
  "dependencies": [
    "motion",
    "@hugeicons/react",
    "@hugeicons/core-free-icons"
  ],
  "registryDependencies": [
    "https://www.craftui.space/r/craftui-base.json",
    "https://www.craftui.space/r/avatar-default.json"
  ],
  "cssVars": {
    "light": {
      "team-surface": "var(--background, oklch(1 0 0))",
      "team-fg": "var(--foreground, oklch(0.145 0 0))",
      "team-fg-soft": "color-mix(in oklab, var(--foreground, oklch(0.145 0 0)) 70%, transparent)",
      "team-fg-muted": "var(--muted-foreground, oklch(0.556 0 0))",
      "team-ring": "var(--ring, oklch(0.708 0 0))"
    },
    "dark": {
      "team-surface": "var(--background, oklch(0.145 0 0))",
      "team-fg": "var(--foreground, oklch(0.985 0 0))",
      "team-fg-soft": "color-mix(in oklab, var(--foreground, oklch(0.985 0 0)) 70%, transparent)",
      "team-fg-muted": "var(--muted-foreground, oklch(0.708 0 0))",
      "team-ring": "var(--ring, oklch(0.556 0 0))"
    }
  },
  "files": [
    {
      "path": "components/craftui/sections/team-cluster-01/default.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport {\n  Compass01Icon,\n  PaintBoardIcon,\n  SourceCodeIcon,\n  CustomerSupportIcon,\n  Rocket01Icon,\n  DocumentValidationIcon,\n} from \"@hugeicons/core-free-icons\";\nimport AvatarGrid, {\n  type AvatarMember,\n} from \"@/components/craftui/blocks/avatar/default\";\n\ntype HugeIcon = React.ComponentProps<typeof HugeiconsIcon>[\"icon\"];\n\nexport type TeamMember = AvatarMember & {\n  icon?: HugeIcon;\n  bio?: string;\n  links?: { label: string; href: string }[];\n};\n\nexport interface TeamCluster01Props {\n  eyebrow?: string;\n  heading?: React.ReactNode;\n  body?: React.ReactNode;\n  members?: TeamMember[];\n  className?: string;\n}\n\nconst TIMING = {\n  heading: 0,\n  body: 0.12,\n  detail: 0.48,\n};\n\nconst EASE = [0.165, 0.84, 0.44, 1] as const;\nconst DURATION = 0.25;\n\nconst DEFAULT_MEMBERS: TeamMember[] = [\n  {\n    id: \"maya\",\n    name: \"Maya Ellis\",\n    role: \"Founder & CEO\",\n    icon: Compass01Icon,\n    src: \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&auto=format&fit=crop&q=80\",\n    cell: [2, 2],\n    bio: \"Started the studio in 2019.\",\n    links: [{ label: \"LinkedIn\", href: \"#\" }],\n  },\n  {\n    id: \"noor\",\n    name: \"Noor Haddad\",\n    role: \"Head of Design\",\n    icon: PaintBoardIcon,\n    src: \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=400&auto=format&fit=crop&q=80\",\n    cell: [2, 3],\n    bio: \"Sets the craft bar, sketch to pixel.\",\n    links: [{ label: \"Portfolio\", href: \"#\" }],\n  },\n  {\n    id: \"tom\",\n    name: \"Tom Brandt\",\n    role: \"Principal Engineer\",\n    icon: SourceCodeIcon,\n    src: \"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=400&auto=format&fit=crop&q=80\",\n    cell: [3, 2],\n    bio: \"Owns the rendering pipeline.\",\n    links: [{ label: \"GitHub\", href: \"#\" }],\n  },\n  {\n    id: \"amir\",\n    name: \"Amir Rahal\",\n    role: \"Support Lead\",\n    icon: CustomerSupportIcon,\n    src: \"https://images.unsplash.com/photo-1519085360753-af0119f7cbe7?w=400&auto=format&fit=crop&q=80\",\n    cell: [3, 4],\n    bio: \"Answers every ticket personally.\",\n    links: [{ label: \"Email\", href: \"#\" }],\n  },\n  {\n    id: \"dev\",\n    name: \"Dev Sharma\",\n    role: \"Product Engineer\",\n    icon: Rocket01Icon,\n    src: \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=400&auto=format&fit=crop&q=80\",\n    cell: [4, 3],\n    bio: \"Builds the parts customers touch most.\",\n    links: [{ label: \"GitHub\", href: \"#\" }],\n  },\n  {\n    id: \"lena\",\n    name: \"Lena Fischer\",\n    role: \"Content Reviewer\",\n    icon: DocumentValidationIcon,\n    src: \"https://images.unsplash.com/photo-1531123897727-8f129e1688ce?w=400&auto=format&fit=crop&q=80\",\n    cell: [4, 4],\n    bio: \"Keeps the documentation honest.\",\n    links: [{ label: \"Writing\", href: \"#\" }],\n  },\n];\n\nexport default function TeamCluster01({\n  eyebrow = \"Know my team\",\n  heading = \"The people behind the work\",\n  body = \"Six of us, one studio, and a shared refusal to ship things that feel almost right.\",\n  members = DEFAULT_MEMBERS,\n  className,\n}: TeamCluster01Props = {}) {\n  const scopeId = React.useId().replace(/:/g, \"\");\n  const reduceMotion = useReducedMotion();\n  const [selectedId, setSelectedId] = React.useState<string | null>(\n    members[0]?.id ?? null,\n  );\n  const [activeId, setActiveId] = React.useState<string | null>(\n    members[0]?.id ?? null,\n  );\n  const rise = (delay: number) => ({\n    initial: reduceMotion ? { opacity: 0 } : { opacity: 0, y: 12 },\n    whileInView: reduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 },\n    viewport: { once: true, amount: 0.3 },\n    transition: { duration: DURATION, ease: EASE, delay },\n  });\n\n  return (\n    <section\n      className={`w-full bg-[var(--team-surface)] py-16 sm:py-20 xl:py-28 ${className ?? \"\"}`}\n    >\n      <style>\n        {`\n          .team-${scopeId} {\n            display: grid;\n            gap: 2.5rem;\n            grid-template-areas: \"copy\" \"cluster\" \"detail\";\n          }\n          @media (min-width: 1280px) {\n            .team-${scopeId} {\n              grid-template-columns: minmax(0, 1fr) minmax(0, 550px);\n              grid-template-areas: \"copy cluster\" \"detail cluster\";\n              align-items: end;\n              column-gap: 1rem;\n              row-gap: 2rem;\n            }\n            .team-${scopeId} [data-role-badge] {\n              display: none;\n            }\n          }\n        `}\n      </style>\n\n      <div\n        className={`team-${scopeId} mx-auto max-w-6xl px-5 sm:px-8 xl:max-w-6xl`}\n      >\n        <div\n          style={{ gridArea: \"copy\" }}\n          className=\"mx-auto max-w-xl text-left md:text-center xl:mx-0 xl:max-w-none xl:text-left\"\n        >\n          <motion.p\n            {...rise(TIMING.heading)}\n            className=\"text-xs font-medium tracking-[0.14em] text-[var(--team-fg-muted)] uppercase\"\n          >\n            {eyebrow}\n          </motion.p>\n          <motion.h2\n            {...rise(TIMING.heading)}\n            className=\"mt-3 text-3xl font-medium tracking-tight text-balance text-[var(--team-fg)] sm:text-4xl xl:text-[2.75rem] xl:leading-[1.1]\"\n          >\n            {heading}\n          </motion.h2>\n          <motion.p\n            {...rise(TIMING.body)}\n            className=\"mx-auto mt-4 max-w-md text-base leading-relaxed text-pretty text-[var(--team-fg-muted)] xl:mx-0\"\n          >\n            {body}\n          </motion.p>\n        </div>\n\n        <div style={{ gridArea: \"cluster\" }} className=\"xl:-ml-[94px]\">\n          <AvatarGrid\n            members={members}\n            selectedId={selectedId}\n            onSelect={setSelectedId}\n            onActiveChange={setActiveId}\n            roleBadges\n            renderBadge={(member) => (\n              <span className=\"block text-left\">\n                <span className=\"block\">{member.name}</span>\n                <span className=\"mt-0.5 block text-[9px] font-normal opacity-75\">\n                  {member.role}\n                </span>\n              </span>\n            )}\n            className=\"!p-0 !justify-start xl:[&>div]:max-w-[600px]\"\n          />\n        </div>\n\n        <motion.div\n          style={{ gridArea: \"detail\" }}\n          {...rise(TIMING.detail)}\n          className=\"hidden md:block\"\n        >\n          <ul className=\"mx-auto max-w-md text-center [--hatch-ink:oklch(0_0_0_/_0.12)] xl:mx-0 xl:text-left dark:[--hatch-ink:oklch(1_0_0_/_0.16)]\">\n            {members.map((member, index) => {\n              const isActive = activeId === member.id;\n              return (\n                <li key={member.id}>\n                  {index > 0 && (\n                    <div\n                      aria-hidden=\"true\"\n                      className=\"h-1\"\n                      style={{\n                        backgroundImage:\n                          \"repeating-linear-gradient(45deg, var(--hatch-ink) 0 1px, transparent 1px 6px)\",\n                      }}\n                    />\n                  )}\n                  <button\n                    type=\"button\"\n                    aria-pressed={isActive}\n                    aria-label={`${member.name} — ${member.role}`}\n                    onClick={() => setSelectedId(member.id)}\n                    onPointerEnter={(event) => {\n                      if (event.pointerType === \"mouse\")\n                        setSelectedId(member.id);\n                    }}\n                    className={`flex w-full cursor-pointer items-start justify-between gap-6 py-2.5 text-sm transition-colors duration-150 ease-out focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[var(--team-ring)] ${\n                      isActive\n                        ? \"font-medium text-[var(--team-fg)]\"\n                        : \"text-[var(--team-fg-muted)] hover:text-[var(--team-fg)]\"\n                    }`}\n                  >\n                    <span className=\"flex min-w-0 shrink-0 items-center gap-2.5 text-left\">\n                      {member.icon && (\n                        <HugeiconsIcon\n                          icon={member.icon}\n                          size={16}\n                          strokeWidth={1.5}\n                          color=\"currentColor\"\n                          className=\"shrink-0\"\n                          aria-hidden=\"true\"\n                        />\n                      )}\n                      {member.role}\n                    </span>\n                    <span className=\"flex min-w-0 flex-col items-end text-right\">\n                      <span\n                        className={`text-xs font-normal transition-colors duration-150 ease-out ${\n                          isActive\n                            ? \"text-[var(--team-fg)]\"\n                            : \"text-[var(--team-fg-soft)]\"\n                        }`}\n                      >\n                        {member.name}\n                      </span>\n                      {member.bio && (\n                        <span className=\"mt-0.5 line-clamp-1 text-xs leading-snug font-normal text-[var(--team-fg-muted)]\">\n                          {member.bio}\n                        </span>\n                      )}\n                    </span>\n                  </button>\n                </li>\n              );\n            })}\n          </ul>\n        </motion.div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "~/components/craftui/sections/team-cluster-01/default.tsx"
    }
  ],
  "meta": {
    "displayName": "Team Cluster 01 - Team Cluster 01",
    "description": "A team section built around the avatar cluster. Perfet to use to showcase your team details in a website.  ",
    "category": "Know My Team",
    "tags": [
      "team",
      "section",
      "about",
      "people",
      "grid",
      "hover"
    ],
    "animationType": "hover"
  }
}