{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "task-card",
  "type": "registry:component",
  "title": "Task Card",
  "description": "A task card you can read at a glance: checklist progress, who's on it, and a due date that warms from grey to amber to red as it slips.",
  "categories": [
    "component",
    "Workspace"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils",
    "https://coss.com/ui/r/avatar.json",
    "https://coss.com/ui/r/button.json",
    "https://coss.com/ui/r/checkbox.json",
    "https://coss.com/ui/r/menu.json",
    "https://coss.com/ui/r/tooltip.json"
  ],
  "files": [
    {
      "path": "registry/devl/task-card.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport {\n  AlertTriangleIcon,\n  ArchiveIcon,\n  CalendarIcon,\n  CheckIcon,\n  ChevronDownIcon,\n  CopyIcon,\n  LinkIcon,\n  MessageSquareIcon,\n  MoreHorizontalIcon,\n  PaperclipIcon,\n  Undo2Icon,\n  UserPlusIcon,\n} from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useEffect, useId, useMemo, useRef, useState } from \"react\";\nimport { Avatar, AvatarFallback } from \"@/components/ui/avatar\";\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n  Menu,\n  MenuCheckboxItem,\n  MenuGroup,\n  MenuGroupLabel,\n  MenuItem,\n  MenuPopup,\n  MenuSeparator,\n  MenuShortcut,\n  MenuTrigger,\n} from \"@/components/ui/menu\";\nimport { Tooltip, TooltipPopup, TooltipTrigger } from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\nexport type TaskTone = \"violet\" | \"sky\" | \"emerald\" | \"amber\" | \"rose\" | \"slate\";\nexport type TaskPriority = \"none\" | \"low\" | \"medium\" | \"high\" | \"urgent\";\n\nexport interface TaskLabel {\n  name: string;\n  tone: TaskTone;\n}\n\nexport interface TaskPerson {\n  id: string;\n  name: string;\n  initials: string;\n  tone?: TaskTone;\n}\n\nexport interface TaskChecklistItem {\n  id: string;\n  text: string;\n  done: boolean;\n}\n\nexport interface Task {\n  id: string;\n  title: string;\n  priority?: TaskPriority;\n  labels?: TaskLabel[];\n  assignees?: string[];\n  checklist?: TaskChecklistItem[];\n  due?: Date | string | null;\n  comments?: number;\n  attachments?: number;\n}\n\nexport type TaskCardAction = \"copy-link\" | \"duplicate\" | \"archive\" | \"restore\";\n\nexport interface TaskCardProps {\n  task: Task;\n  people?: TaskPerson[];\n  now?: Date;\n  defaultExpanded?: boolean;\n  onChange?: (task: Task) => void;\n  onAction?: (action: TaskCardAction, task: Task) => void;\n  className?: string;\n}\n\nconst labelTones: Record<TaskTone, { chip: string; dot: string }> = {\n  violet: { chip: \"bg-violet-500/10 text-violet-700 dark:bg-violet-500/16 dark:text-violet-300\", dot: \"bg-violet-500\" },\n  sky: { chip: \"bg-sky-500/10 text-sky-700 dark:bg-sky-500/16 dark:text-sky-300\", dot: \"bg-sky-500\" },\n  emerald: {\n    chip: \"bg-emerald-500/10 text-emerald-700 dark:bg-emerald-500/16 dark:text-emerald-300\",\n    dot: \"bg-emerald-500\",\n  },\n  amber: { chip: \"bg-amber-500/12 text-amber-700 dark:bg-amber-500/16 dark:text-amber-300\", dot: \"bg-amber-500\" },\n  rose: { chip: \"bg-rose-500/10 text-rose-700 dark:bg-rose-500/16 dark:text-rose-300\", dot: \"bg-rose-500\" },\n  slate: { chip: \"bg-muted text-muted-foreground\", dot: \"bg-muted-foreground\" },\n};\n\nconst personTones: Record<TaskTone, string> = {\n  violet: \"bg-violet-600 text-white\",\n  sky: \"bg-sky-700 text-white\",\n  emerald: \"bg-emerald-700 text-white\",\n  amber: \"bg-amber-500 text-amber-950\",\n  rose: \"bg-rose-700 text-white\",\n  slate: \"bg-muted-foreground text-background\",\n};\n\nconst priorityLabel: Record<TaskPriority, string> = {\n  none: \"No priority\",\n  low: \"Low priority\",\n  medium: \"Medium priority\",\n  high: \"High priority\",\n  urgent: \"Urgent\",\n};\n\nconst DAY = 86_400_000;\nconst quick =\n  \"text-muted-foreground transition-[scale,background-color] duration-150 ease-out after:absolute after:inset-x-0 after:-inset-y-1 active:scale-[0.94]\";\nconst startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\nconst toDate = (d: Date | string | null | undefined) => (d == null ? null : d instanceof Date ? d : new Date(d));\nconst shortDate = (d: Date) => d.toLocaleDateString(\"en-US\", { month: \"short\", day: \"numeric\" });\n\ntype DueState = { key: string; label: string; tone: string; Icon: typeof CalendarIcon; hint: string };\n\nfunction dueState(due: Date | null, now: Date, complete: boolean): DueState | null {\n  if (!due) return null;\n  const diff = Math.round((startOfDay(due) - startOfDay(now)) / DAY);\n  const date = shortDate(due);\n  if (complete) {\n    return {\n      key: \"done\",\n      label: date,\n      tone: \"bg-success/10 text-success-foreground dark:bg-success/16\",\n      Icon: CheckIcon,\n      hint: `Checklist complete, due ${date}`,\n    };\n  }\n  if (diff <= -3) {\n    return {\n      key: \"overdue\",\n      label: `${-diff}d late`,\n      tone: \"bg-destructive/10 text-destructive-foreground dark:bg-destructive/16\",\n      Icon: AlertTriangleIcon,\n      hint: `Was due ${date}`,\n    };\n  }\n  if (diff < 0) {\n    return {\n      key: \"late\",\n      label: `${-diff}d late`,\n      tone: \"bg-warning/12 text-warning-foreground dark:bg-warning/16\",\n      Icon: AlertTriangleIcon,\n      hint: `Was due ${date}`,\n    };\n  }\n  if (diff === 0) {\n    return { key: \"today\", label: \"Today\", tone: \"bg-info/10 text-info-foreground dark:bg-info/16\", Icon: CalendarIcon, hint: `Due today, ${date}` };\n  }\n  if (diff === 1) {\n    return { key: \"soon\", label: \"Tomorrow\", tone: \"bg-muted text-foreground\", Icon: CalendarIcon, hint: `Due ${date}` };\n  }\n  return { key: \"later\", label: date, tone: \"bg-muted text-muted-foreground\", Icon: CalendarIcon, hint: `Due ${date}` };\n}\n\nfunction PriorityGlyph({ level }: { level: TaskPriority }) {\n  if (level === \"urgent\") {\n    return (\n      <span className=\"flex size-4 items-center justify-center rounded-[calc(var(--radius)*0.4)] bg-destructive font-bold text-[10px] text-white leading-none\">\n        !\n      </span>\n    );\n  }\n  const filled = { none: 0, low: 1, medium: 2, high: 3 }[level];\n  return (\n    <svg aria-hidden className=\"size-4\" viewBox=\"0 0 16 16\">\n      {[0, 1, 2].map((i) => (\n        <rect\n          className={i < filled ? \"fill-foreground/80\" : \"fill-foreground/16\"}\n          height={4 + i * 3}\n          key={i}\n          rx={1}\n          width={3}\n          x={2.5 + i * 4}\n          y={12.5 - (4 + i * 3)}\n        />\n      ))}\n    </svg>\n  );\n}\n\nfunction RollingCount({ value, reduce }: { value: number; reduce: boolean | null }) {\n  return (\n    <span className=\"relative inline-flex overflow-hidden tabular-nums\">\n      <AnimatePresence initial={false} mode=\"popLayout\">\n        <motion.span\n          animate={{ y: 0, opacity: 1 }}\n          exit={reduce ? { opacity: 0 } : { y: \"-100%\", opacity: 0 }}\n          initial={reduce ? { opacity: 0 } : { y: \"100%\", opacity: 0 }}\n          key={value}\n          transition={{ type: \"spring\", stiffness: 500, damping: 34 }}\n        >\n          {value}\n        </motion.span>\n      </AnimatePresence>\n    </span>\n  );\n}\n\nfunction ProgressRing({ value, complete, reduce }: { value: number; complete: boolean; reduce: boolean | null }) {\n  const r = 6.5;\n  return (\n    <span className=\"relative flex size-4 shrink-0 items-center justify-center\">\n      <svg aria-hidden className=\"size-4 -rotate-90\" viewBox=\"0 0 16 16\">\n        <circle className=\"stroke-foreground/12\" cx={8} cy={8} fill=\"none\" r={r} strokeWidth={2} />\n        <motion.circle\n          animate={{ pathLength: value }}\n          className={cn(\"transition-colors duration-300\", complete ? \"stroke-success\" : \"stroke-foreground/72\")}\n          cx={8}\n          cy={8}\n          fill=\"none\"\n          initial={false}\n          r={r}\n          strokeLinecap=\"round\"\n          strokeWidth={2}\n          transition={reduce ? { duration: 0 } : { type: \"spring\", stiffness: 220, damping: 26 }}\n        />\n      </svg>\n    </span>\n  );\n}\n\nexport function TaskCard({\n  task,\n  people = [],\n  now: nowProp,\n  defaultExpanded = false,\n  onChange,\n  onAction,\n  className,\n}: TaskCardProps) {\n  const reduce = useReducedMotion();\n  const listId = useId();\n  const [now] = useState(() => nowProp ?? new Date());\n  const [checklist, setChecklist] = useState<TaskChecklistItem[]>(task.checklist ?? []);\n  const [assignees, setAssignees] = useState<string[]>(task.assignees ?? []);\n  const [due, setDue] = useState<Date | null>(toDate(task.due));\n  const [expanded, setExpanded] = useState(defaultExpanded);\n  const [openMenu, setOpenMenu] = useState<string | null>(null);\n  const [archived, setArchived] = useState(false);\n  const [copied, setCopied] = useState(false);\n  const copyTimer = useRef<ReturnType<typeof setTimeout>>(undefined);\n  const archiveRef = useRef<HTMLButtonElement>(null);\n  const cardRef = useRef<HTMLElement>(null);\n\n  useEffect(() => () => clearTimeout(copyTimer.current), []);\n\n  const done = checklist.filter((i) => i.done).length;\n  const total = checklist.length;\n  const complete = total > 0 && done === total;\n  const dueInfo = dueState(due, nowProp ?? now, complete);\n  const peopleById = useMemo(() => new Map(people.map((p) => [p.id, p])), [people]);\n  const assigned = assignees.map((id) => peopleById.get(id)).filter((p): p is TaskPerson => Boolean(p));\n  const current = (patch: Partial<Task>): Task => ({ ...task, checklist, assignees, due, ...patch });\n\n  const spring = reduce ? { duration: 0 } : { type: \"spring\" as const, stiffness: 420, damping: 34 };\n\n  const toggleItem = (id: string) => {\n    const next = checklist.map((i) => (i.id === id ? { ...i, done: !i.done } : i));\n    setChecklist(next);\n    onChange?.(current({ checklist: next }));\n  };\n\n  const toggleAssignee = (id: string, on: boolean) => {\n    const next = on ? [...assignees.filter((a) => a !== id), id] : assignees.filter((a) => a !== id);\n    setAssignees(next);\n    onChange?.(current({ assignees: next }));\n  };\n\n  const setDueIn = (days: number | null) => {\n    const next = days == null ? null : new Date(startOfDay(nowProp ?? now) + days * DAY);\n    setDue(next);\n    onChange?.(current({ due: next }));\n  };\n\n  const action = (a: TaskCardAction) => {\n    if (a === \"copy-link\") {\n      navigator.clipboard?.writeText(`#${task.id}`).catch(() => {});\n      setCopied(true);\n      clearTimeout(copyTimer.current);\n      copyTimer.current = setTimeout(() => setCopied(false), 1600);\n    }\n    if (a === \"archive\") {\n      setArchived(true);\n      requestAnimationFrame(() => archiveRef.current?.focus());\n    }\n    if (a === \"restore\") {\n      setArchived(false);\n      requestAnimationFrame(() => cardRef.current?.focus());\n    }\n    onAction?.(a, current({}));\n  };\n\n  const menuProps = (name: string) => ({\n    open: openMenu === name,\n    onOpenChange: (open: boolean) => setOpenMenu((o) => (open ? name : o === name ? null : o)),\n  });\n\n  const priority = task.priority ?? \"none\";\n\n  return (\n    <motion.div\n      className={cn(\"w-full max-w-[340px]\", className)}\n      layout={!reduce}\n      style={{ borderRadius: 16 }}\n      transition={spring}\n    >\n      <AnimatePresence initial={false} mode=\"popLayout\">\n        {archived ? (\n          <motion.div\n            animate={{ opacity: 1, scale: 1 }}\n            className=\"flex items-center gap-2 rounded-2xl border border-dashed bg-card/60 px-3 py-2.5 text-muted-foreground text-xs\"\n            exit={{ opacity: 0, scale: 0.98 }}\n            initial={{ opacity: 0, scale: 0.98 }}\n            key=\"archived\"\n            transition={spring}\n          >\n            <ArchiveIcon className=\"size-3.5\" />\n            <span className=\"min-w-0 flex-1 truncate\">\n              <span className=\"font-mono\">{task.id}</span> archived\n            </span>\n            <Button onClick={() => action(\"restore\")} ref={archiveRef} size=\"xs\" variant=\"ghost\">\n              <Undo2Icon />\n              Undo\n            </Button>\n          </motion.div>\n        ) : (\n          <motion.article\n            animate={{ opacity: 1, scale: 1 }}\n            aria-label={task.title}\n            className=\"group/card relative rounded-2xl border bg-card p-3.5 text-card-foreground shadow-xs/5 outline-none transition-[border-color,box-shadow] hover:border-foreground/16 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\"\n            exit={{ opacity: 0, scale: 0.98 }}\n            initial={{ opacity: 0, scale: 0.98 }}\n            key=\"card\"\n            ref={cardRef}\n            tabIndex={0}\n            transition={spring}\n          >\n            <header className=\"flex h-6 items-center gap-1.5 pe-24\">\n              <Tooltip>\n                <TooltipTrigger\n                  render={<span aria-label={priorityLabel[priority]} className=\"flex text-foreground\" role=\"img\" />}\n                >\n                  <PriorityGlyph level={priority} />\n                </TooltipTrigger>\n                <TooltipPopup>{priorityLabel[priority]}</TooltipPopup>\n              </Tooltip>\n              <AnimatePresence initial={false} mode=\"popLayout\">\n                <motion.span\n                  animate={{ opacity: 1, y: 0 }}\n                  className={cn(\n                    \"inline-flex items-center gap-1 font-mono text-xs\",\n                    copied ? \"text-success-foreground\" : \"text-muted-foreground\",\n                  )}\n                  exit={reduce ? { opacity: 0 } : { opacity: 0, y: -6 }}\n                  initial={reduce ? { opacity: 0 } : { opacity: 0, y: 6 }}\n                  key={copied ? \"copied\" : \"id\"}\n                  transition={{ duration: 0.16 }}\n                >\n                  {copied ? (\n                    <>\n                      <CheckIcon className=\"size-3\" /> Link copied\n                    </>\n                  ) : (\n                    task.id\n                  )}\n                </motion.span>\n              </AnimatePresence>\n            </header>\n\n            <div\n              className={cn(\n                \"absolute end-2.5 top-2.5 flex items-center gap-0.5 rounded-lg border bg-popover p-0.5 shadow-xs/5 transition-[opacity,translate,scale] duration-200 ease-out\",\n                \"pointer-events-none translate-y-0.5 scale-95 opacity-0\",\n                \"group-focus-within/card:pointer-events-auto group-focus-within/card:translate-y-0 group-focus-within/card:scale-100 group-focus-within/card:opacity-100\",\n                \"group-hover/card:pointer-events-auto group-hover/card:translate-y-0 group-hover/card:scale-100 group-hover/card:opacity-100\",\n                \"pointer-coarse:pointer-events-auto pointer-coarse:translate-y-0 pointer-coarse:scale-100 pointer-coarse:opacity-100\",\n                openMenu && \"pointer-events-auto translate-y-0 scale-100 opacity-100\",\n                \"motion-reduce:transition-opacity\",\n              )}\n              data-slot=\"quick-actions\"\n            >\n              <Menu {...menuProps(\"assign\")}>\n                <MenuTrigger\n                  render={<Button aria-label=\"Assign people\" className={quick} size=\"icon-xs\" variant=\"ghost\" />}\n                >\n                  <UserPlusIcon />\n                </MenuTrigger>\n                <MenuPopup align=\"end\" className=\"w-48\">\n                  <MenuGroup>\n                    <MenuGroupLabel>Assign to</MenuGroupLabel>\n                    {people.map((p) => (\n                      <MenuCheckboxItem\n                        checked={assignees.includes(p.id)}\n                        closeOnClick={false}\n                        key={p.id}\n                        onCheckedChange={(on) => toggleAssignee(p.id, on)}\n                      >\n                        <span className=\"flex items-center gap-2\">\n                          <Avatar className=\"[--avatar-size:--spacing(5)]\">\n                            <AvatarFallback className={cn(\"text-[9px]\", personTones[p.tone ?? \"slate\"])}>\n                              {p.initials}\n                            </AvatarFallback>\n                          </Avatar>\n                          {p.name}\n                        </span>\n                      </MenuCheckboxItem>\n                    ))}\n                  </MenuGroup>\n                </MenuPopup>\n              </Menu>\n\n              <Menu {...menuProps(\"due\")}>\n                <MenuTrigger\n                  render={<Button aria-label=\"Set due date\" className={quick} size=\"icon-xs\" variant=\"ghost\" />}\n                >\n                  <CalendarIcon />\n                </MenuTrigger>\n                <MenuPopup align=\"end\" className=\"w-48\">\n                  <MenuGroup>\n                    <MenuGroupLabel>Due date</MenuGroupLabel>\n                    {[\n                      { label: \"Today\", days: 0 },\n                      { label: \"Tomorrow\", days: 1 },\n                      { label: \"Next week\", days: 7 },\n                    ].map((o) => (\n                      <MenuItem key={o.label} onClick={() => setDueIn(o.days)}>\n                        {o.label}\n                        <MenuShortcut className=\"tracking-normal\">\n                          {shortDate(new Date(startOfDay(nowProp ?? now) + o.days * DAY))}\n                        </MenuShortcut>\n                      </MenuItem>\n                    ))}\n                  </MenuGroup>\n                  <MenuSeparator />\n                  <MenuItem disabled={!due} onClick={() => setDueIn(null)}>\n                    Clear due date\n                  </MenuItem>\n                </MenuPopup>\n              </Menu>\n\n              <Menu {...menuProps(\"more\")}>\n                <MenuTrigger\n                  render={<Button aria-label=\"More actions\" className={quick} size=\"icon-xs\" variant=\"ghost\" />}\n                >\n                  <MoreHorizontalIcon />\n                </MenuTrigger>\n                <MenuPopup align=\"end\" className=\"w-44\">\n                  <MenuItem onClick={() => action(\"copy-link\")}>\n                    <LinkIcon />\n                    Copy link\n                  </MenuItem>\n                  <MenuItem onClick={() => action(\"duplicate\")}>\n                    <CopyIcon />\n                    Duplicate\n                  </MenuItem>\n                  <MenuSeparator />\n                  <MenuItem onClick={() => action(\"archive\")} variant=\"destructive\">\n                    <ArchiveIcon />\n                    Archive\n                  </MenuItem>\n                </MenuPopup>\n              </Menu>\n            </div>\n\n            <h3 className=\"mt-1.5 text-pretty font-medium text-sm leading-snug\">{task.title}</h3>\n\n            {task.labels && task.labels.length > 0 && (\n              <ul aria-label=\"Labels\" className=\"mt-2.5 flex flex-wrap gap-1\">\n                {task.labels.map((l) => (\n                  <li\n                    className={cn(\n                      \"inline-flex h-5 items-center gap-1.5 rounded-full px-2 font-medium text-xs\",\n                      labelTones[l.tone].chip,\n                    )}\n                    key={l.name}\n                  >\n                    <span aria-hidden className={cn(\"size-1.5 rounded-full\", labelTones[l.tone].dot)} />\n                    {l.name}\n                  </li>\n                ))}\n              </ul>\n            )}\n\n            {total > 0 && (\n              <div className=\"mt-3 rounded-xl bg-muted/60 dark:bg-muted/40\">\n                <button\n                  aria-controls={listId}\n                  aria-expanded={expanded}\n                  className=\"flex w-full cursor-pointer items-center gap-2.5 rounded-xl px-2.5 py-2 text-left outline-none transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring\"\n                  onClick={() => setExpanded((e) => !e)}\n                  type=\"button\"\n                >\n                  <ProgressRing complete={complete} reduce={reduce} value={total ? done / total : 0} />\n                  <span className=\"font-medium text-xs\">Checklist</span>\n                  <span className=\"relative h-1 flex-1 overflow-hidden rounded-full bg-foreground/10\">\n                    <motion.span\n                      animate={{ scaleX: total ? done / total : 0 }}\n                      className={cn(\n                        \"absolute inset-0 origin-left rounded-full transition-colors duration-300\",\n                        complete ? \"bg-success\" : \"bg-foreground/60\",\n                      )}\n                      initial={false}\n                      transition={reduce ? { duration: 0 } : { type: \"spring\", stiffness: 220, damping: 26 }}\n                    />\n                  </span>\n                  <span className=\"inline-flex text-muted-foreground text-xs tabular-nums\">\n                    <RollingCount reduce={reduce} value={done} />/{total}\n                  </span>\n                  <ChevronDownIcon\n                    className={cn(\n                      \"size-3.5 text-muted-foreground transition-transform duration-200\",\n                      expanded && \"rotate-180\",\n                    )}\n                  />\n                </button>\n                <AnimatePresence initial={false}>\n                  {expanded && (\n                    <motion.div\n                      animate={{ height: \"auto\", opacity: 1 }}\n                      className=\"overflow-hidden\"\n                      exit={{ height: 0, opacity: 0 }}\n                      id={listId}\n                      initial={{ height: 0, opacity: 0 }}\n                      transition={reduce ? { duration: 0 } : { type: \"spring\", stiffness: 380, damping: 36 }}\n                    >\n                      <ul className=\"flex flex-col gap-0.5 px-1 pb-1.5\">\n                        {checklist.map((item) => (\n                          <li key={item.id}>\n                            <label className=\"flex cursor-pointer items-start gap-2.5 rounded-lg px-1.5 py-1.5 transition-colors hover:bg-background/70 dark:hover:bg-background/40\">\n                              <Checkbox\n                                checked={item.done}\n                                className=\"mt-px\"\n                                onCheckedChange={() => toggleItem(item.id)}\n                              />\n                              <span\n                                className={cn(\n                                  \"relative text-xs leading-4 transition-colors duration-200\",\n                                  item.done ? \"text-muted-foreground\" : \"text-foreground\",\n                                )}\n                              >\n                                {item.text}\n                                <motion.span\n                                  animate={{ scaleX: item.done ? 1 : 0 }}\n                                  aria-hidden\n                                  className=\"absolute inset-x-0 top-1/2 h-px origin-left bg-muted-foreground/70\"\n                                  initial={false}\n                                  transition={reduce ? { duration: 0 } : { type: \"spring\", stiffness: 300, damping: 30 }}\n                                />\n                              </span>\n                            </label>\n                          </li>\n                        ))}\n                      </ul>\n                    </motion.div>\n                  )}\n                </AnimatePresence>\n              </div>\n            )}\n\n            <footer className=\"mt-3 flex h-6 items-center gap-3 text-muted-foreground text-xs\">\n              <AnimatePresence initial={false} mode=\"popLayout\">\n                {dueInfo && (\n                  <motion.span\n                    animate={{ opacity: 1, scale: 1 }}\n                    className=\"flex\"\n                    exit={{ opacity: 0, scale: 0.9 }}\n                    initial={reduce ? { opacity: 0 } : { opacity: 0, scale: 0.9 }}\n                    key={dueInfo.key + dueInfo.label}\n                    layout={!reduce}\n                    transition={spring}\n                  >\n                    <Tooltip>\n                      <TooltipTrigger\n                        render={\n                          <span\n                            aria-label={dueInfo.hint}\n                            className={cn(\n                              \"inline-flex h-6 items-center gap-1 rounded-full px-2 font-medium tabular-nums\",\n                              dueInfo.tone,\n                            )}\n                            role=\"img\"\n                          />\n                        }\n                      >\n                        <dueInfo.Icon className=\"size-3.5\" />\n                        {dueInfo.label}\n                      </TooltipTrigger>\n                      <TooltipPopup>{dueInfo.hint}</TooltipPopup>\n                    </Tooltip>\n                  </motion.span>\n                )}\n              </AnimatePresence>\n              {(task.comments ?? 0) > 0 && (\n                <motion.span\n                  className=\"inline-flex items-center gap-1 tabular-nums\"\n                  layout={!reduce ? \"position\" : false}\n                  transition={spring}\n                >\n                  <MessageSquareIcon aria-hidden className=\"size-3.5\" />\n                  {task.comments}\n                  <span className=\"sr-only\">comments</span>\n                </motion.span>\n              )}\n              {(task.attachments ?? 0) > 0 && (\n                <motion.span\n                  className=\"inline-flex items-center gap-1 tabular-nums\"\n                  layout={!reduce ? \"position\" : false}\n                  transition={spring}\n                >\n                  <PaperclipIcon aria-hidden className=\"size-3.5\" />\n                  {task.attachments}\n                  <span className=\"sr-only\">attachments</span>\n                </motion.span>\n              )}\n              <ul aria-label=\"Assignees\" className=\"-me-0.5 ms-auto flex items-center\">\n                <AnimatePresence initial={false} mode=\"popLayout\">\n                  {assigned.length === 0 && (\n                    <motion.li\n                      animate={{ opacity: 1 }}\n                      exit={{ opacity: 0 }}\n                      initial={{ opacity: 0 }}\n                      key=\"none\"\n                      transition={{ duration: 0.15 }}\n                    >\n                      <span className=\"flex size-6 items-center justify-center rounded-full border border-dashed border-muted-foreground/40\">\n                        <UserPlusIcon className=\"size-3\" />\n                        <span className=\"sr-only\">Unassigned</span>\n                      </span>\n                    </motion.li>\n                  )}\n                  {assigned.map((p, i) => (\n                    <motion.li\n                      animate={{ opacity: 1, scale: 1 }}\n                      className={cn(\"relative rounded-full bg-card p-0.5\", i > 0 && \"-ms-2\")}\n                      exit={{ opacity: 0, scale: 0.85 }}\n                      initial={reduce ? { opacity: 0 } : { opacity: 0, scale: 0.85 }}\n                      key={p.id}\n                      layout={!reduce}\n                      style={{ zIndex: assigned.length - i }}\n                      transition={spring}\n                    >\n                      <Tooltip>\n                        <TooltipTrigger\n                          render={\n                            <Avatar\n                              aria-label={p.name}\n                              className=\"[--avatar-size:--spacing(6)]\"\n                              role=\"img\"\n                            />\n                          }\n                        >\n                          <AvatarFallback className={cn(\"text-[10px]\", personTones[p.tone ?? \"slate\"])}>\n                            {p.initials}\n                          </AvatarFallback>\n                        </TooltipTrigger>\n                        <TooltipPopup>{p.name}</TooltipPopup>\n                      </Tooltip>\n                    </motion.li>\n                  ))}\n                </AnimatePresence>\n              </ul>\n            </footer>\n          </motion.article>\n        )}\n      </AnimatePresence>\n    </motion.div>\n  );\n}\n"
    }
  ]
}