{"name":"kanban-list","type":"registry:ui","files":[{"path":"kanban-list.tsx","type":"registry:ui","content":"\"use client\"\n\nimport {\n  animate,\n  motion,\n  useMotionValue,\n  useReducedMotion,\n  useSpring,\n  useTransform,\n  useVelocity,\n  type MotionValue,\n} from \"motion/react\"\nimport {\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  type CSSProperties,\n  type KeyboardEvent,\n  type PointerEvent as ReactPointerEvent,\n} from \"react\"\nimport { flushSync } from \"react-dom\"\n\nconst FRAME_WIDTH = 1448\nconst q = (px: number) => `${(px / FRAME_WIDTH) * 100}cqw`\n\nconst LAND_EASE = [0.25, 0.7, 0.2, 1] as const\nconst SLOT_EASE = [0.23, 1, 0.32, 1] as const\nconst TILT_AT = 1400\nconst TILT_MAX = 7\n\nexport type KanbanListStage = \"to-call\" | \"called\" | \"trial\" | \"signed\" | \"dropped\"\nexport type KanbanListView = \"kanban\" | \"list\"\n\nexport interface KanbanListItem {\n  id: string\n  name: string\n  stage: KanbanListStage\n  action: string\n  note: string\n  age: string\n  booked?: boolean\n}\n\nexport interface KanbanListProps {\n  defaultItems?: KanbanListItem[]\n  onItemsChange?: (items: KanbanListItem[]) => void\n  columns?: KanbanListStage[]\n  view?: KanbanListView\n  className?: string\n  ariaLabel?: string\n}\n\ntype Rect = {\n  top: number\n  right: number\n  bottom: number\n  left: number\n  width: number\n  height: number\n}\n\ntype Target = { stage: KanbanListStage; index: number }\n\ntype Snapshot = {\n  cols: Map<KanbanListStage, Rect>\n  cards: Map<string, Rect>\n  board: Rect\n  gap: number\n  scrollOffset: number\n}\n\ntype DragRecord = {\n  id: string\n  lead: KanbanListItem\n  from: KanbanListStage\n  fromIndex: number\n  rect: Rect\n  rootRect: Rect\n  startX: number\n  startY: number\n  pointerX: number\n  pointerY: number\n  shot: Snapshot\n  phase: \"dragging\" | \"landing\"\n}\n\ntype SlotArrangement = {\n  from: Record<string, number>\n  to: Record<string, number>\n}\n\nconst STAGES: ReadonlyArray<{\n  id: KanbanListStage\n  name: string\n  tone: string\n  soft: string\n  icon: \"phone\" | \"outgoing\" | \"calendar\" | \"check\" | \"close\"\n}> = [\n  { id: \"to-call\", name: \"To call\", tone: \"#4F7CF7\", soft: \"#EAF0FF\", icon: \"phone\" },\n  { id: \"called\", name: \"Called\", tone: \"#A06CDC\", soft: \"#F3ECFB\", icon: \"outgoing\" },\n  { id: \"trial\", name: \"Trial booked\", tone: \"#D8863B\", soft: \"#FFF2E6\", icon: \"calendar\" },\n  { id: \"signed\", name: \"Signed\", tone: \"#2E9B68\", soft: \"#E6F6EE\", icon: \"check\" },\n  { id: \"dropped\", name: \"Dropped\", tone: \"#A1A1AA\", soft: \"#EFEFF1\", icon: \"close\" },\n]\n\nconst DEFAULT_ITEMS: KanbanListItem[] = [\n  { id: \"ava\", name: \"Ava Rodriguez\", stage: \"to-call\", action: \"+1 415 555 0142\", note: \"Referred by Marcus at Northstar\", age: \"12m\" },\n  { id: \"liam\", name: \"Liam Chen\", stage: \"to-call\", action: \"+1 206 555 0188\", note: \"Asked about the team plan\", age: \"38m\" },\n  { id: \"sophie\", name: \"Sophie Williams\", stage: \"to-call\", action: \"+44 20 7946 0831\", note: \"Downloaded the pricing guide\", age: \"2h\" },\n  { id: \"noah\", name: \"Noah Thompson\", stage: \"called\", action: \"+1 312 555 0194\", note: \"Follow up after finance review\", age: \"1d\" },\n  { id: \"maya\", name: \"Maya Patel\", stage: \"called\", action: \"+1 646 555 0129\", note: \"Interested in annual billing\", age: \"1d\" },\n  { id: \"ethan\", name: \"Ethan Brooks\", stage: \"called\", action: \"+1 617 555 0165\", note: \"Needs SSO and audit logs\", age: \"2d\" },\n  { id: \"isla\", name: \"Isla Campbell\", stage: \"trial\", action: \"Tue, 10:30 AM\", note: \"Invite product and operations\", age: \"3h\", booked: true },\n  { id: \"lucas\", name: \"Lucas Martin\", stage: \"trial\", action: \"Wed, 2:00 PM\", note: \"Review migration workflow\", age: \"6h\", booked: true },\n  { id: \"mia\", name: \"Mia Anderson\", stage: \"trial\", action: \"Fri, 9:00 AM\", note: \"Wants a security overview\", age: \"1d\", booked: true },\n  { id: \"oliver\", name: \"Oliver Jensen\", stage: \"signed\", action: \"+45 33 12 44 08\", note: \"Growth plan · 18 seats\", age: \"2d\" },\n  { id: \"amelia\", name: \"Amelia Davis\", stage: \"signed\", action: \"+1 718 555 0173\", note: \"Business plan · 32 seats\", age: \"4d\" },\n  { id: \"henry\", name: \"Henry Wilson\", stage: \"dropped\", action: \"+1 213 555 0116\", note: \"Timing changed; revisit in Q4\", age: \"6d\" },\n]\n\nconst styles = `\n  .kanban-list { --kanban-list-ink: #171717; --kanban-list-muted: #737373; --kanban-list-note: #8F8F8F; --kanban-list-quiet: #9CA3AF; --kanban-list-marker: #9B9B9B; --kanban-list-marker-quiet: #BDBDBD; --kanban-list-tray: #FAFAFB; --kanban-list-card: #FFFFFF; --kanban-list-hover: #F5F5F6; --kanban-list-border: rgba(24, 24, 27, 0.08); --kanban-list-count: #ECECEF; --kanban-list-count-ink: #71717A; --kanban-list-fade: var(--background, #FFFFFF); position: relative; width: 100%; color: var(--kanban-list-ink); font-family: Inter, ui-sans-serif, system-ui, sans-serif; }\n  .dark .kanban-list, .kanban-list.dark { --kanban-list-ink: #F4F4F5; --kanban-list-muted: #B4B4BC; --kanban-list-note: #92929C; --kanban-list-quiet: #7D7D89; --kanban-list-marker: #8B8B95; --kanban-list-marker-quiet: #676771; --kanban-list-tray: #18181B; --kanban-list-card: #242427; --kanban-list-hover: #2B2B2F; --kanban-list-border: rgba(255, 255, 255, 0.085); --kanban-list-count: #2E2E33; --kanban-list-count-ink: #B4B4BC; --kanban-list-fade: var(--background, #101012); }\n  .kanban-list * { box-sizing: border-box; }\n  .kanban-list__scroller { position: relative; overflow-x: auto; overflow-y: hidden; padding-inline: ${q(44)}; padding-block: ${q(10)} ${q(24)}; scrollbar-width: thin; scrollbar-color: var(--kanban-list-border) transparent; overscroll-behavior-inline: contain; }\n  .kanban-list__board { position: relative; display: flex; align-items: flex-start; width: max-content; min-width: 100%; gap: ${q(12)}; }\n  .kanban-list__column { width: ${q(300)}; min-height: ${q(470)}; flex: 0 0 ${q(300)}; padding: ${q(6)}; border-radius: ${q(14)}; background: var(--kanban-list-tray); border: ${q(1)} solid var(--kanban-list-border); }\n  .kanban-list--preview-two-columns .kanban-list__board { width: 100%; min-width: 0; }\n  .kanban-list--preview-two-columns .kanban-list__column { width: calc((100% - ${q(12)}) / 2); flex-basis: calc((100% - ${q(12)}) / 2); }\n  .kanban-list--preview-scroll { height: 100%; min-height: 0; }\n  .kanban-list--preview-scroll[data-view=\"list\"] .kanban-list__scroller { height: 100%; max-height: 100%; }\n  .kanban-list__header { height: ${q(32)}; display: flex; align-items: center; gap: ${q(8)}; padding-inline: ${q(10)}; }\n  .kanban-list__stage-icon { width: ${q(16)}; height: ${q(16)}; display: grid; place-items: center; flex: 0 0 auto; border-radius: ${q(5)}; }\n  .kanban-list__stage-icon svg { width: ${q(10)}; height: ${q(10)}; }\n  .kanban-list__stage-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${q(12)}; line-height: ${q(16)}; font-weight: 600; }\n  .kanban-list__count-wrap { position: relative; margin-left: auto; width: ${q(18)}; height: ${q(18)}; overflow: hidden; border-radius: ${q(9)}; background: var(--kanban-list-count); color: var(--kanban-list-count-ink); }\n  .kanban-list__count { position: absolute; inset: 0; display: grid; place-items: center; font-size: ${q(9.5)}; line-height: ${q(12)}; font-weight: 600; font-variant-numeric: tabular-nums; }\n  .kanban-list__list { position: relative; min-height: ${q(420)}; }\n  .kanban-list__slot { width: 100%; pointer-events: none; }\n  .kanban-list__item { width: 100%; }\n  .kanban-list__card { position: relative; display: block; width: 100%; min-width: 0; appearance: none; border: 0; margin: 0; padding: ${q(12)} ${q(16)} ${q(15)}; border-radius: ${q(10)}; background: var(--kanban-list-card); color: inherit; text-align: left; cursor: grab; touch-action: none; user-select: none; box-shadow: 0 ${q(1)} ${q(2)} rgba(0, 0, 0, 0.08), 0 ${q(4)} ${q(12)} rgba(0, 0, 0, 0.055), inset 0 0 0 ${q(1)} var(--kanban-list-border); transition: box-shadow 160ms cubic-bezier(0.19, 1, 0.22, 1), background-color 160ms cubic-bezier(0.19, 1, 0.22, 1); }\n  .kanban-list__card:hover { box-shadow: 0 ${q(2)} ${q(4)} rgba(0, 0, 0, 0.1), 0 ${q(7)} ${q(16)} rgba(0, 0, 0, 0.08), inset 0 0 0 ${q(1)} var(--kanban-list-border); }\n  .kanban-list__card:active { cursor: grabbing; }\n  .kanban-list__card:focus-visible { outline: ${q(2)} solid #4F7CF7; outline-offset: ${q(2)}; }\n  .kanban-list__row { display: grid; min-width: 0; grid-template-columns: ${q(16)} minmax(0, 1fr); column-gap: ${q(8)}; align-items: center; }\n  .kanban-list__row + .kanban-list__row--action { margin-top: ${q(10)}; }\n  .kanban-list__row--note { margin-top: ${q(8)}; }\n  .kanban-list__marker { width: ${q(16)}; height: ${q(16)}; display: grid; place-items: center; }\n  .kanban-list__marker svg { display: block; width: ${q(13)}; height: ${q(13)}; color: var(--kanban-list-marker); }\n  .kanban-list__row--note .kanban-list__marker svg { width: ${q(12)}; height: ${q(12)}; color: var(--kanban-list-marker-quiet); }\n  .kanban-list__name { min-width: 0; padding-right: ${q(34)}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${q(14)}; line-height: ${q(17.5)}; font-weight: 500; color: var(--kanban-list-ink); }\n  .kanban-list__action { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: ${q(12)}; line-height: ${q(18)}; font-weight: 400; color: var(--kanban-list-muted); font-variant-numeric: tabular-nums; }\n  .kanban-list__note { min-width: 0; display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 1; font-size: ${q(11.5)}; line-height: ${q(17.4)}; font-weight: 400; color: var(--kanban-list-note); }\n  .kanban-list__age { position: absolute; top: ${q(13)}; right: ${q(16)}; font-size: ${q(10)}; line-height: ${q(14)}; font-weight: 400; color: var(--kanban-list-quiet); font-variant-numeric: tabular-nums; }\n  .kanban-list__overlay-layer { position: absolute; inset: 0; z-index: 20; pointer-events: none; overflow: visible; }\n  .kanban-list__overlay { position: absolute; left: 0; top: 0; transform-origin: 50% 50%; will-change: transform; }\n  .kanban-list__overlay .kanban-list__card { height: 100%; cursor: grabbing; box-shadow: none; }\n  .kanban-list__tone-ring { position: absolute; inset: 0; z-index: 2; pointer-events: none; border-radius: inherit; box-shadow: inset 0 0 0 ${q(1.5)} color-mix(in srgb, var(--kanban-list-ink) 18%, transparent); }\n  .kanban-list__signed-mark { position: absolute; z-index: 3; right: ${q(12)}; bottom: ${q(10)}; width: ${q(20)}; height: ${q(20)}; display: grid; place-items: center; border-radius: 50%; color: #39AD79; background: color-mix(in srgb, currentColor 15%, var(--kanban-list-card)); box-shadow: 0 ${q(2)} ${q(6)} rgba(46, 155, 104, 0.16); }\n  .kanban-list__signed-mark svg { width: ${q(12)}; height: ${q(12)}; }\n  .kanban-list__fade { position: absolute; z-index: 10; top: 0; bottom: 0; width: ${q(38)}; pointer-events: none; opacity: 0; transition: opacity 160ms cubic-bezier(0.19, 1, 0.22, 1); }\n  .kanban-list__fade[data-visible=\"true\"] { opacity: 1; }\n  .kanban-list__fade--left { left: 0; background: linear-gradient(90deg, var(--kanban-list-fade), transparent); }\n  .kanban-list__fade--right { right: 0; background: linear-gradient(270deg, var(--kanban-list-fade), transparent); }\n  .kanban-list[data-view=\"list\"] .kanban-list__scroller { max-height: var(--kanban-list-list-max-height, ${q(840)}); overflow-x: hidden; overflow-y: auto; overscroll-behavior-inline: auto; overscroll-behavior-block: contain; }\n  .kanban-list[data-view=\"list\"] .kanban-list__board { width: 100%; min-width: 0; flex-direction: column; gap: ${q(10)}; }\n  .kanban-list[data-view=\"list\"] .kanban-list__column { width: 100%; min-height: 0; flex: none; }\n  .kanban-list[data-view=\"list\"] .kanban-list__list { min-height: 0; overflow: hidden; border-radius: ${q(10)}; background: var(--kanban-list-card); box-shadow: inset 0 0 0 ${q(1)} var(--kanban-list-border); }\n  .kanban-list[data-view=\"list\"] .kanban-list__card { height: ${q(44)}; display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1.4fr) minmax(0, 2fr) ${q(60)}; align-items: center; gap: ${q(12)}; padding: 0 ${q(16)}; border-radius: 0; background: transparent; box-shadow: inset 0 -${q(1)} 0 var(--kanban-list-border); }\n  .kanban-list[data-view=\"list\"] [data-last=\"true\"] .kanban-list__card { box-shadow: none; }\n  .kanban-list[data-view=\"list\"] .kanban-list__card:hover { background: var(--kanban-list-hover); box-shadow: inset 0 -${q(1)} 0 var(--kanban-list-border); }\n  .kanban-list[data-view=\"list\"] [data-last=\"true\"] .kanban-list__card:hover { box-shadow: none; }\n  .kanban-list[data-view=\"list\"] .kanban-list__overlay .kanban-list__card { border-radius: inherit; background: var(--kanban-list-card); box-shadow: none; }\n  .kanban-list[data-view=\"list\"] .kanban-list__name { padding-right: 0; font-size: ${q(13)}; line-height: ${q(17)}; }\n  .kanban-list[data-view=\"list\"] .kanban-list__action, .kanban-list[data-view=\"list\"] .kanban-list__note { display: flex; align-items: center; min-width: 0; gap: ${q(8)}; font-size: ${q(12.5)}; line-height: ${q(17)}; }\n  .kanban-list[data-view=\"list\"] .kanban-list__note { color: var(--kanban-list-note); }\n  .kanban-list[data-view=\"list\"] .kanban-list__cell-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n  .kanban-list[data-view=\"list\"] .kanban-list__marker { flex: 0 0 ${q(16)}; }\n  .kanban-list[data-view=\"list\"] .kanban-list__marker svg { width: ${q(12)}; height: ${q(12)}; }\n  .kanban-list[data-view=\"list\"] .kanban-list__note .kanban-list__marker svg { width: ${q(12)}; height: ${q(12)}; color: var(--kanban-list-marker-quiet); }\n  .kanban-list[data-view=\"list\"] .kanban-list__age { position: static; justify-self: end; min-width: 0; font-size: ${q(10)}; line-height: ${q(14)}; text-align: right; }\n  .kanban-list[data-view=\"list\"] .kanban-list__fade { left: 0; right: 0; width: auto; height: ${q(28)}; }\n  .kanban-list[data-view=\"list\"] .kanban-list__fade--left { top: 0; bottom: auto; background: linear-gradient(180deg, var(--kanban-list-fade), transparent); }\n  .kanban-list[data-view=\"list\"] .kanban-list__fade--right { top: auto; bottom: 0; background: linear-gradient(0deg, var(--kanban-list-fade), transparent); }\n  .dark .kanban-list__stage-icon, .kanban-list.dark .kanban-list__stage-icon { background: color-mix(in srgb, currentColor 15%, transparent) !important; }\n  .kanban-list__instructions, .kanban-list__live { position: absolute; width: ${q(1)}; height: ${q(1)}; padding: 0; margin: -${q(1)}; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }\n  @media (prefers-reduced-motion: reduce) { .kanban-list__card { transition: none; } }\n`\n\nfunction copyRect(rect: DOMRect): Rect {\n  return {\n    top: rect.top,\n    right: rect.right,\n    bottom: rect.bottom,\n    left: rect.left,\n    width: rect.width,\n    height: rect.height,\n  }\n}\n\nfunction stageMeta(stage: KanbanListStage) {\n  return STAGES.find((item) => item.id === stage) ?? STAGES[0]\n}\n\nfunction StageGlyph({ name }: { name: (typeof STAGES)[number][\"icon\"] }) {\n  const common = { fill: \"none\", stroke: \"currentColor\", strokeLinecap: \"round\" as const, strokeLinejoin: \"round\" as const, strokeWidth: 1.65 }\n  return (\n    <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n      {name === \"phone\" && <path {...common} d=\"M4.3 2.6 6 2.2l1.1 3-1.2 1c.7 1.6 1.9 2.8 3.5 3.5l1-1.2 3 1.1-.4 1.8c-.2.8-.9 1.4-1.8 1.3-4.8-.5-8.6-4.3-9.1-9.1-.1-.5.3-.9.8-1Z\" />}\n      {name === \"outgoing\" && <><path {...common} d=\"M3 8.2c.7-2.8 2.4-4.5 5.2-5.2\" /><path {...common} d=\"M7.8 2.8h3.4v3.4M12.6 9.6v1.8c0 .7-.5 1.2-1.2 1.2H4.6c-.7 0-1.2-.5-1.2-1.2V8\" /></>}\n      {name === \"calendar\" && <><rect {...common} x=\"2.5\" y=\"3.6\" width=\"11\" height=\"9.6\" rx=\"1.8\" /><path {...common} d=\"M5.2 2.4v2.3m5.6-2.3v2.3M2.5 6.5h11\" /></>}\n      {name === \"check\" && <path {...common} d=\"m3.2 8.2 3 3 6.6-6.6\" />}\n      {name === \"close\" && <path {...common} d=\"m4 4 8 8m0-8-8 8\" />}\n    </svg>\n  )\n}\n\nfunction PhoneGlyph({ booked }: { booked?: boolean }) {\n  return booked ? <StageGlyph name=\"calendar\" /> : <StageGlyph name=\"phone\" />\n}\n\nfunction NoteGlyph() {\n  return (\n    <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n      <path d=\"M3 3.2h10v7.4H7l-3.2 2.2v-2.2H3z\" fill=\"currentColor\" />\n    </svg>\n  )\n}\n\nfunction KanbanListCardContent({ lead, view }: { lead: KanbanListItem; view: KanbanListView }) {\n  if (view === \"list\") {\n    return (\n      <>\n        <span className=\"kanban-list__name\">{lead.name}</span>\n        <span className=\"kanban-list__action\">\n          <span className=\"kanban-list__marker\"><PhoneGlyph booked={lead.booked} /></span>\n          <span className=\"kanban-list__cell-text\">{lead.action}</span>\n        </span>\n        <span className=\"kanban-list__note\">\n          <span className=\"kanban-list__marker\"><NoteGlyph /></span>\n          <span className=\"kanban-list__cell-text\">{lead.note}</span>\n        </span>\n        <span className=\"kanban-list__age\">{lead.age}</span>\n      </>\n    )\n  }\n\n  return (\n    <>\n      <span className=\"kanban-list__age\">{lead.age}</span>\n      <span className=\"kanban-list__row\">\n        <span className=\"kanban-list__marker\" aria-hidden=\"true\" />\n        <span className=\"kanban-list__name\">{lead.name}</span>\n      </span>\n      <span className=\"kanban-list__row kanban-list__row--action\">\n        <span className=\"kanban-list__marker\"><PhoneGlyph booked={lead.booked} /></span>\n        <span className=\"kanban-list__action\">{lead.action}</span>\n      </span>\n      <span className=\"kanban-list__row kanban-list__row--note\">\n        <span className=\"kanban-list__marker\"><NoteGlyph /></span>\n        <span className=\"kanban-list__note\">{lead.note}</span>\n      </span>\n    </>\n  )\n}\n\nfunction RollingCount({ value }: { value: number }) {\n  return (\n    <span className=\"kanban-list__count-wrap\" aria-label={`${value} items`}>\n      <motion.span\n        key={value}\n        className=\"kanban-list__count\"\n        initial={{ y: q(12), opacity: 0 }}\n        animate={{ y: 0, opacity: 1 }}\n        exit={{ y: `-${q(12)}`, opacity: 0 }}\n        transition={{ duration: 0.18, ease: [0.19, 1, 0.22, 1] }}\n      >\n        {value}\n      </motion.span>\n    </span>\n  )\n}\n\nfunction DragOverlay({\n  drag,\n  target,\n  mx,\n  my,\n  screenX,\n  screenY,\n  scaleValue,\n  view,\n  tiltGain,\n  lift,\n  ringOpacity,\n  radius,\n}: {\n  drag: DragRecord\n  target: Target | null\n  mx: MotionValue<number>\n  my: MotionValue<number>\n  screenX: MotionValue<number>\n  screenY: MotionValue<number>\n  scaleValue: MotionValue<number>\n  view: KanbanListView\n  tiltGain: MotionValue<number>\n  lift: MotionValue<number>\n  ringOpacity: MotionValue<number>\n  radius: MotionValue<number>\n}) {\n  const reduce = useReducedMotion()\n  const velocity = useVelocity(view === \"list\" ? screenY : screenX)\n  const tiltRaw = useTransform(velocity, [-TILT_AT, TILT_AT], [-TILT_MAX, TILT_MAX], { clamp: true })\n  const tiltSpring = useSpring(tiltRaw, { stiffness: 300, damping: 30, mass: 0.6 })\n  const tilt = useTransform(() => (reduce ? 0 : tiltSpring.get() * tiltGain.get()))\n  const shadow = useTransform(lift, (value) => {\n    const a = Math.max(0, Math.min(1, value))\n    return `0 ${q(2 + a * 8)} ${q(5 + a * 21)} rgba(0,0,0,${0.08 + a * 0.12}), 0 ${q(1 + a * 2)} ${q(2 + a * 6)} rgba(0,0,0,${0.06 + a * 0.06}), inset 0 0 0 ${q(1)} var(--kanban-list-border)`\n  })\n  return (\n    <motion.div\n      className=\"kanban-list__overlay\"\n      style={{\n        x: mx,\n        y: my,\n        rotate: tilt,\n        scale: scaleValue,\n        width: drag.rect.width,\n        height: drag.rect.height,\n        borderRadius: radius,\n        boxShadow: shadow,\n      }}\n    >\n      <div className=\"kanban-list__card\" style={{ borderRadius: \"inherit\" }}>\n        <KanbanListCardContent lead={drag.lead} view={view} />\n      </div>\n      <motion.span className=\"kanban-list__tone-ring\" style={{ opacity: ringOpacity }} />\n      {target?.stage === \"signed\" ? (\n        <motion.span\n          className=\"kanban-list__signed-mark\"\n          initial={{ opacity: 0 }}\n          animate={{ opacity: 1 }}\n          transition={{ duration: 0.16, ease: [0.19, 1, 0.22, 1] }}\n        >\n          <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n            <motion.path\n              d=\"m3 8.3 3 3 7-7\"\n              fill=\"none\"\n              stroke=\"currentColor\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              strokeWidth=\"2\"\n              initial={{ pathLength: 0 }}\n              animate={{ pathLength: 1 }}\n              transition={{ duration: 0.22, ease: [0.19, 1, 0.22, 1] }}\n            />\n          </svg>\n        </motion.span>\n      ) : null}\n    </motion.div>\n  )\n}\n\nfunction mergeClassNames(...values: Array<string | undefined>) {\n  return values.filter(Boolean).join(\" \")\n}\n\nfunction reorderLeads(all: KanbanListItem[], id: string, target: Target) {\n  const moved = all.find((lead) => lead.id === id)\n  if (!moved) return all\n  const buckets = new Map<KanbanListStage, KanbanListItem[]>(STAGES.map((stage) => [stage.id, []]))\n  for (const lead of all) {\n    if (lead.id !== id) buckets.get(lead.stage)?.push(lead)\n  }\n  buckets.get(target.stage)?.splice(target.index, 0, { ...moved, stage: target.stage })\n  return STAGES.flatMap((stage) => buckets.get(stage.id) ?? [])\n}\n\nexport function KanbanList({\n  defaultItems = DEFAULT_ITEMS,\n  onItemsChange,\n  columns,\n  view = \"kanban\",\n  className,\n  ariaLabel = \"Kanban list\",\n}: KanbanListProps) {\n  const isList = view === \"list\"\n  const [leads, setLeads] = useState<KanbanListItem[]>(() => defaultItems.map((lead) => ({ ...lead })))\n  const [drag, setDrag] = useState<DragRecord | null>(null)\n  const [target, setTarget] = useState<Target | null>(null)\n  const [announcement, setAnnouncement] = useState(\"\")\n  const [slots, setSlots] = useState<SlotArrangement>({ from: {}, to: {} })\n  const [scrollEdges, setScrollEdges] = useState({ leading: false, trailing: false })\n  const reduce = useReducedMotion()\n\n  const rootRef = useRef<HTMLDivElement>(null)\n  const scrollerRef = useRef<HTMLDivElement>(null)\n  const boardRef = useRef<HTMLDivElement>(null)\n  const columnRefs = useRef(new Map<KanbanListStage, HTMLElement>())\n  const listRefs = useRef(new Map<KanbanListStage, HTMLDivElement>())\n  const cardRefs = useRef(new Map<string, HTMLButtonElement>())\n  const dragRef = useRef<DragRecord | null>(null)\n  const targetRef = useRef<Target | null>(null)\n  const pressRef = useRef<DragRecord | null>(null)\n  const cleanupPointerRef = useRef<(() => void) | null>(null)\n  const autoScrollRef = useRef<number | null>(null)\n  const slotAnimationRef = useRef<ReturnType<typeof animate> | null>(null)\n  const slotProgress = useMotionValue(1)\n  const slotHeightRef = useRef(0)\n\n  const mx = useMotionValue(0)\n  const my = useMotionValue(0)\n  const screenX = useMotionValue(0)\n  const screenY = useMotionValue(0)\n  const scaleValue = useMotionValue(1)\n  const tiltGain = useMotionValue(1)\n  const lift = useMotionValue(0)\n  const ringOpacity = useMotionValue(0)\n  const radius = useMotionValue(0)\n\n  const displayedStages = useMemo(\n    () => columns?.length ? STAGES.filter((stage) => columns.includes(stage.id)) : STAGES,\n    [columns],\n  )\n\n  const grouped = useMemo(() => {\n    const map = new Map<KanbanListStage, KanbanListItem[]>(STAGES.map((stage) => [stage.id, []]))\n    for (const lead of leads) map.get(lead.stage)?.push(lead)\n    return map\n  }, [leads])\n\n  useEffect(() => {\n    const root = rootRef.current\n    if (!root) return\n    const paint = (value: number) => {\n      root.querySelectorAll<HTMLElement>(\"[data-slotwrap]\").forEach((slot) => {\n        const from = Number.parseFloat(slot.style.getPropertyValue(\"--slot-from\")) || 0\n        const delta = Number.parseFloat(slot.style.getPropertyValue(\"--slot-delta\")) || 0\n        slot.style.paddingTop = `${from + delta * value}px`\n      })\n    }\n    paint(slotProgress.get())\n    return slotProgress.on(\"change\", paint)\n  }, [slotProgress])\n\n  useEffect(() => () => {\n    cleanupPointerRef.current?.()\n    if (autoScrollRef.current !== null) cancelAnimationFrame(autoScrollRef.current)\n    slotAnimationRef.current?.stop()\n  }, [])\n\n  useEffect(() => {\n    const controls = animate(ringOpacity, target ? 1 : 0, {\n      duration: reduce ? 0 : 0.14,\n      ease: [0.19, 1, 0.22, 1],\n    })\n    return () => controls.stop()\n  }, [reduce, ringOpacity, target])\n\n  const scale = useCallback((value: number) => {\n    const width = rootRef.current?.getBoundingClientRect().width ?? FRAME_WIDTH\n    return (value / FRAME_WIDTH) * width\n  }, [])\n\n  useEffect(() => {\n    const scroller = scrollerRef.current\n    if (!scroller) return\n    const update = () => {\n      const edge = scale(1)\n      const position = isList ? scroller.scrollTop : scroller.scrollLeft\n      const max = isList\n        ? Math.max(0, scroller.scrollHeight - scroller.clientHeight)\n        : Math.max(0, scroller.scrollWidth - scroller.clientWidth)\n      const next = {\n        leading: position > edge,\n        trailing: position < max - edge,\n      }\n      setScrollEdges((current) => current.leading === next.leading && current.trailing === next.trailing ? current : next)\n    }\n    update()\n    scroller.addEventListener(\"scroll\", update, { passive: true })\n    const observer = new ResizeObserver(update)\n    observer.observe(scroller)\n    if (boardRef.current) observer.observe(boardRef.current)\n    return () => {\n      scroller.removeEventListener(\"scroll\", update)\n      observer.disconnect()\n    }\n  }, [displayedStages, isList, scale])\n\n  const currentSlotValues = useCallback(() => {\n    const current: Record<string, number> = {}\n    rootRef.current?.querySelectorAll<HTMLElement>(\"[data-slot-key]\").forEach((slot) => {\n      const key = slot.dataset.slotKey\n      const padding = Number.parseFloat(getComputedStyle(slot).paddingTop) || 0\n      if (key && padding > 0.01) current[key] = padding\n    })\n    return current\n  }, [])\n\n  const setSlotTarget = useCallback((next: Target | null, immediate = false) => {\n    slotAnimationRef.current?.stop()\n    const nextValues = next ? { [`${next.stage}:${next.index}`]: slotHeightRef.current } : {}\n    if (immediate || reduce) {\n      setSlots({ from: nextValues, to: nextValues })\n      slotProgress.set(1)\n      return\n    }\n    const current = currentSlotValues()\n    setSlots({ from: current, to: nextValues })\n    slotProgress.set(0)\n    requestAnimationFrame(() => {\n      slotAnimationRef.current = animate(slotProgress, 1, {\n        duration: 0.24,\n        ease: SLOT_EASE,\n      })\n    })\n  }, [currentSlotValues, reduce, slotProgress])\n\n  const measureSnapshot = useCallback((): Snapshot | null => {\n    const scroller = scrollerRef.current\n    const board = boardRef.current\n    if (!scroller || !board) return null\n    const cols = new Map<KanbanListStage, Rect>()\n    const cards = new Map<string, Rect>()\n    columnRefs.current.forEach((node, stage) => cols.set(stage, copyRect(node.getBoundingClientRect())))\n    cardRefs.current.forEach((node, id) => cards.set(id, copyRect(node.getBoundingClientRect())))\n    return {\n      cols,\n      cards,\n      board: copyRect(board.getBoundingClientRect()),\n      gap: isList ? 0 : scale(8),\n      scrollOffset: isList ? scroller.scrollTop : scroller.scrollLeft,\n    }\n  }, [isList, scale])\n\n  const resolveTarget = useCallback((record: DragRecord, clientX: number, clientY: number): Target | null => {\n    const scroller = scrollerRef.current\n    const currentScroll = scroller ? (isList ? scroller.scrollTop : scroller.scrollLeft) : record.shot.scrollOffset\n    const scrollDelta = currentScroll - record.shot.scrollOffset\n    if (isList) {\n      const bound = scale(80)\n      if (clientX < record.shot.board.left - bound || clientX > record.shot.board.right + bound) return null\n    } else {\n      const bound = scale(60)\n      if (clientY < record.shot.board.top - bound || clientY > record.shot.board.bottom + bound) return null\n    }\n\n    const along = (isList ? clientY : clientX) + scrollDelta\n    let selected: KanbanListStage | null = null\n    let best = Number.POSITIVE_INFINITY\n    for (const stage of displayedStages) {\n      const rect = record.shot.cols.get(stage.id)\n      if (!rect) continue\n      const start = isList ? rect.top : rect.left\n      const end = isList ? rect.bottom : rect.right\n      const edgeDistance = along < start ? start - along : along > end ? along - end : 0\n      if (edgeDistance < best) {\n        best = edgeDistance\n        selected = stage.id\n      }\n    }\n    if (!selected) return null\n\n    const contentY = clientY + (isList ? scrollDelta : 0)\n    const ids = leads.filter((lead) => lead.stage === selected).map((lead) => lead.id)\n    let index = 0\n    for (const id of ids) {\n      const rect = record.shot.cards.get(id)\n      if (rect && contentY > rect.top + rect.height / 2) index += 1\n    }\n    if (selected === record.from && index > record.fromIndex) index -= 1\n    const max = ids.length - (selected === record.from ? 1 : 0)\n    return { stage: selected, index: Math.max(0, Math.min(index, max)) }\n  }, [displayedStages, isList, leads, scale])\n\n  const applyTarget = useCallback((next: Target | null, immediate = false) => {\n    const previous = targetRef.current\n    if (previous?.stage === next?.stage && previous?.index === next?.index) return\n    targetRef.current = next\n    setTarget(next)\n    setSlotTarget(next, immediate)\n  }, [setSlotTarget])\n\n  const updateFromPointer = useCallback((clientX: number, clientY: number) => {\n    const record = dragRef.current\n    if (!record || record.phase !== \"dragging\") return\n    record.pointerX = clientX\n    record.pointerY = clientY\n    mx.set(record.rect.left - record.rootRect.left + clientX - record.startX)\n    my.set(record.rect.top - record.rootRect.top + clientY - record.startY)\n    screenX.set(record.rect.left + clientX - record.startX)\n    screenY.set(record.rect.top + clientY - record.startY)\n    applyTarget(resolveTarget(record, clientX, clientY))\n  }, [applyTarget, mx, my, resolveTarget, screenX, screenY])\n\n  const stopAutoScroll = useCallback(() => {\n    if (autoScrollRef.current !== null) cancelAnimationFrame(autoScrollRef.current)\n    autoScrollRef.current = null\n  }, [])\n\n  const startAutoScroll = useCallback(() => {\n    stopAutoScroll()\n    const tick = () => {\n      const record = dragRef.current\n      const scroller = scrollerRef.current\n      if (!record || record.phase !== \"dragging\" || !scroller) return\n      const rect = scroller.getBoundingClientRect()\n      const zone = scale(90)\n      const maxStep = scale(22)\n      let step = 0\n      const pointer = isList ? record.pointerY : record.pointerX\n      const start = isList ? rect.top : rect.left\n      const end = isList ? rect.bottom : rect.right\n      if (pointer < start + zone) step = -maxStep * (1 - Math.max(0, pointer - start) / zone)\n      else if (pointer > end - zone) step = maxStep * (1 - Math.max(0, end - pointer) / zone)\n      if (step !== 0) {\n        const before = isList ? scroller.scrollTop : scroller.scrollLeft\n        const max = isList\n          ? scroller.scrollHeight - scroller.clientHeight\n          : scroller.scrollWidth - scroller.clientWidth\n        const next = Math.max(0, Math.min(max, before + step))\n        if (isList) scroller.scrollTop = next\n        else scroller.scrollLeft = next\n        if (next !== before) updateFromPointer(record.pointerX, record.pointerY)\n      }\n      autoScrollRef.current = requestAnimationFrame(tick)\n    }\n    autoScrollRef.current = requestAnimationFrame(tick)\n  }, [isList, scale, stopAutoScroll, updateFromPointer])\n\n  const commitMove = useCallback((id: string, next: Target) => {\n    const updated = reorderLeads(leads, id, next)\n    setLeads(updated)\n    onItemsChange?.(updated)\n    const moved = leads.find((lead) => lead.id === id)\n    setAnnouncement(`${moved?.name ?? \"Item\"} moved to ${stageMeta(next.stage).name}, position ${next.index + 1}.`)\n  }, [leads, onItemsChange])\n\n  const finishDrag = useCallback((record: DragRecord, destination: Target) => {\n    flushSync(() => {\n      commitMove(record.id, destination)\n      setDrag(null)\n      setTarget(null)\n      setSlots({ from: {}, to: {} })\n      slotProgress.set(1)\n    })\n    dragRef.current = null\n    targetRef.current = null\n    lift.set(0)\n    scaleValue.set(1)\n    ringOpacity.set(0)\n  }, [commitMove, lift, ringOpacity, scaleValue, slotProgress])\n\n  const land = useCallback((record: DragRecord, destination: Target) => {\n    record.phase = \"landing\"\n    stopAutoScroll()\n    targetRef.current = destination\n    setTarget(destination)\n    setSlotTarget(destination, true)\n\n    if (reduce) {\n      finishDrag(record, destination)\n      return\n    }\n\n    requestAnimationFrame(async () => {\n      const root = rootRef.current\n      const list = listRefs.current.get(destination.stage)\n      const scopedSlot = list?.querySelector<HTMLElement>(`[data-slot-key=\"${destination.stage}:${destination.index}\"]`)\n      if (!root || !list || !scopedSlot) {\n        finishDrag(record, destination)\n        return\n      }\n\n      const rootRect = root.getBoundingClientRect()\n      const slotRect = scopedSlot.getBoundingClientRect()\n      let closingAbove = 0\n      root.querySelectorAll<HTMLElement>(\"[data-slotwrap]\").forEach((node) => {\n        if (node === scopedSlot) return\n        const rect = node.getBoundingClientRect()\n        const overlaps = rect.left < slotRect.right && rect.right > slotRect.left\n        if (overlaps && rect.top < slotRect.top) closingAbove += Number.parseFloat(getComputedStyle(node).paddingTop) || 0\n      })\n\n      const targetX = slotRect.left - rootRect.left\n      const targetY = slotRect.top - rootRect.top + (!isList && destination.index > 0 ? record.shot.gap : 0) - closingAbove\n      const distance = Math.hypot(targetX - mx.get(), targetY - my.get())\n      const duration = destination.stage === \"dropped\"\n        ? Math.min(0.4, 0.26 + distance / 2400)\n        : Math.min(0.32, 0.18 + distance / 2400)\n\n      const flights = [\n        animate(mx, targetX, { type: \"tween\", duration, ease: LAND_EASE }),\n        animate(my, targetY, { type: \"tween\", duration, ease: LAND_EASE }),\n        animate(tiltGain, 0, { duration: duration * 0.55, ease: [0.77, 0, 0.175, 1] }),\n        animate(lift, 0, { duration: duration * 0.74, ease: [0.19, 1, 0.22, 1] }),\n        animate(scaleValue, 1, { duration: duration * 0.8, ease: [0.19, 1, 0.22, 1] }),\n        animate(radius, scale(10), { duration: duration * 0.84, ease: [0.77, 0, 0.175, 1] }),\n        animate(ringOpacity, 0, { duration: duration * 0.9, ease: \"linear\" }),\n      ]\n      await Promise.all(flights)\n      finishDrag(record, destination)\n    })\n  }, [finishDrag, isList, lift, mx, my, radius, reduce, ringOpacity, scale, scaleValue, setSlotTarget, stopAutoScroll, tiltGain])\n\n  const beginDrag = useCallback((record: DragRecord) => {\n    dragRef.current = record\n    slotHeightRef.current = record.rect.height + record.shot.gap\n    mx.set(record.rect.left - record.rootRect.left)\n    my.set(record.rect.top - record.rootRect.top)\n    screenX.set(record.rect.left)\n    screenY.set(record.rect.top)\n    tiltGain.set(1)\n    lift.set(1)\n    scaleValue.set(reduce ? 1 : 1.04)\n    ringOpacity.set(1)\n    radius.set(scale(12))\n    setDrag(record)\n    const initial = resolveTarget(record, record.pointerX, record.pointerY) ?? { stage: record.from, index: record.fromIndex }\n    targetRef.current = initial\n    setTarget(initial)\n    setSlotTarget(initial, true)\n    setAnnouncement(`${record.lead.name} picked up from ${stageMeta(record.from).name}.`)\n    startAutoScroll()\n  }, [lift, mx, my, radius, reduce, resolveTarget, ringOpacity, scale, scaleValue, screenX, screenY, setSlotTarget, startAutoScroll, tiltGain])\n\n  const onPointerDown = useCallback((event: ReactPointerEvent<HTMLButtonElement>, lead: KanbanListItem) => {\n    if (event.button !== 0 || dragRef.current) return\n    const shot = measureSnapshot()\n    const card = cardRefs.current.get(lead.id)\n    const root = rootRef.current\n    if (!shot || !card || !root) return\n    const rect = copyRect(card.getBoundingClientRect())\n    const fromIndex = (grouped.get(lead.stage) ?? []).findIndex((item) => item.id === lead.id)\n    const record: DragRecord = {\n      id: lead.id,\n      lead,\n      from: lead.stage,\n      fromIndex,\n      rect,\n      rootRect: copyRect(root.getBoundingClientRect()),\n      startX: event.clientX,\n      startY: event.clientY,\n      pointerX: event.clientX,\n      pointerY: event.clientY,\n      shot,\n      phase: \"dragging\",\n    }\n    pressRef.current = record\n\n    const onMove = (moveEvent: PointerEvent) => {\n      const pending = pressRef.current\n      if (!pending) return\n      pending.pointerX = moveEvent.clientX\n      pending.pointerY = moveEvent.clientY\n      const travelled = Math.hypot(moveEvent.clientX - pending.startX, moveEvent.clientY - pending.startY)\n      if (!dragRef.current && travelled >= scale(4)) beginDrag(pending)\n      if (dragRef.current) {\n        moveEvent.preventDefault()\n        updateFromPointer(moveEvent.clientX, moveEvent.clientY)\n      }\n    }\n\n    const cleanup = () => {\n      window.removeEventListener(\"pointermove\", onMove)\n      window.removeEventListener(\"pointerup\", onUp)\n      window.removeEventListener(\"pointercancel\", onUp)\n      cleanupPointerRef.current = null\n    }\n    const onUp = () => {\n      cleanup()\n      pressRef.current = null\n      const active = dragRef.current\n      if (!active || active.phase !== \"dragging\") return\n      const destination = targetRef.current ?? { stage: active.from, index: active.fromIndex }\n      land(active, destination)\n    }\n\n    cleanupPointerRef.current?.()\n    cleanupPointerRef.current = cleanup\n    window.addEventListener(\"pointermove\", onMove, { passive: false })\n    window.addEventListener(\"pointerup\", onUp, { once: true })\n    window.addEventListener(\"pointercancel\", onUp, { once: true })\n  }, [beginDrag, grouped, land, measureSnapshot, scale, updateFromPointer])\n\n  const onCardKeyDown = useCallback((event: KeyboardEvent<HTMLButtonElement>, lead: KanbanListItem) => {\n    const stageIndex = displayedStages.findIndex((stage) => stage.id === lead.stage)\n    const stageLeads = grouped.get(lead.stage) ?? []\n    const leadIndex = stageLeads.findIndex((item) => item.id === lead.id)\n    let destination: Target | null = null\n    if (event.key === \"ArrowLeft\" && stageIndex > 0) destination = { stage: displayedStages[stageIndex - 1].id, index: (grouped.get(displayedStages[stageIndex - 1].id) ?? []).length }\n    if (event.key === \"ArrowRight\" && stageIndex < displayedStages.length - 1) destination = { stage: displayedStages[stageIndex + 1].id, index: (grouped.get(displayedStages[stageIndex + 1].id) ?? []).length }\n    if (event.key === \"ArrowUp\" && leadIndex > 0) destination = { stage: lead.stage, index: leadIndex - 1 }\n    if (event.key === \"ArrowDown\" && leadIndex < stageLeads.length - 1) destination = { stage: lead.stage, index: leadIndex + 1 }\n    if (!destination) return\n    event.preventDefault()\n    commitMove(lead.id, destination)\n    requestAnimationFrame(() => cardRefs.current.get(lead.id)?.focus())\n  }, [commitMove, displayedStages, grouped])\n\n  const slotStyle = useCallback((key: string): CSSProperties => {\n    const from = slots.from[key] ?? 0\n    const to = slots.to[key] ?? 0\n    const progress = slotProgress.get()\n    return {\n      \"--slot-from\": from,\n      \"--slot-delta\": to - from,\n      paddingTop: `${from + (to - from) * progress}px`,\n    } as CSSProperties\n  }, [slotProgress, slots])\n\n  return (\n    <section\n      ref={rootRef}\n      className={mergeClassNames(\"kanban-list\", className)}\n      style={{ containerType: \"inline-size\" }}\n      data-view={view}\n      aria-label={ariaLabel}\n    >\n      <style>{styles}</style>\n      <p id=\"kanban-list-instructions\" className=\"kanban-list__instructions\">\n        Drag an item between stages. With a keyboard, focus an item and use the arrow keys to move it.\n      </p>\n      <div className=\"kanban-list__live\" aria-live=\"polite\">{announcement}</div>\n      <div ref={scrollerRef} className=\"kanban-list__scroller\">\n        <div ref={boardRef} className=\"kanban-list__board\">\n          {displayedStages.map((stage) => {\n            const stageLeads = grouped.get(stage.id) ?? []\n            const visible = drag ? stageLeads.filter((lead) => lead.id !== drag.id) : stageLeads\n            return (\n              <section\n                key={stage.id}\n                ref={(node) => { if (node) columnRefs.current.set(stage.id, node); else columnRefs.current.delete(stage.id) }}\n                className=\"kanban-list__column\"\n                aria-labelledby={`lead-stage-${stage.id}`}\n              >\n                <header className=\"kanban-list__header\">\n                  <span className=\"kanban-list__stage-icon\" style={{ color: stage.tone, background: stage.soft }}>\n                    <StageGlyph name={stage.icon} />\n                  </span>\n                  <span id={`lead-stage-${stage.id}`} className=\"kanban-list__stage-name\">{stage.name}</span>\n                  <RollingCount value={stageLeads.length} />\n                </header>\n                <div\n                  ref={(node) => { if (node) listRefs.current.set(stage.id, node); else listRefs.current.delete(stage.id) }}\n                  className=\"kanban-list__list\"\n                >\n                  {visible.map((lead, index) => {\n                    const slotKey = `${stage.id}:${index}`\n                    return (\n                      <div key={lead.id} data-item-wrap data-last={index === visible.length - 1}>\n                        <div data-slotwrap data-slot-key={slotKey} className=\"kanban-list__slot\" style={slotStyle(slotKey)} />\n                        <motion.div\n                          layout\n                          className=\"kanban-list__item\"\n                          style={{ marginTop: isList || index === 0 ? 0 : q(8) }}\n                          transition={{ layout: reduce ? { duration: 0 } : { duration: 0.24, ease: SLOT_EASE } }}\n                        >\n                          <button\n                            ref={(node) => { if (node) cardRefs.current.set(lead.id, node); else cardRefs.current.delete(lead.id) }}\n                            type=\"button\"\n                            className=\"kanban-list__card\"\n                            aria-describedby=\"kanban-list-instructions\"\n                            aria-label={`${lead.name}, ${stage.name}. Use arrow keys to move.`}\n                            onPointerDown={(event) => onPointerDown(event, lead)}\n                            onKeyDown={(event) => onCardKeyDown(event, lead)}\n                          >\n                            <KanbanListCardContent lead={lead} view={view} />\n                          </button>\n                        </motion.div>\n                      </div>\n                    )\n                  })}\n                  <div\n                    data-slotwrap\n                    data-slot-key={`${stage.id}:${visible.length}`}\n                    className=\"kanban-list__slot\"\n                    style={slotStyle(`${stage.id}:${visible.length}`)}\n                  />\n                </div>\n              </section>\n            )\n          })}\n        </div>\n      </div>\n      <div className=\"kanban-list__fade kanban-list__fade--left\" data-visible={scrollEdges.leading} aria-hidden=\"true\" />\n      <div className=\"kanban-list__fade kanban-list__fade--right\" data-visible={scrollEdges.trailing} aria-hidden=\"true\" />\n      <div className=\"kanban-list__overlay-layer\" aria-hidden=\"true\">\n        {drag ? (\n          <DragOverlay\n            drag={drag}\n            target={target}\n            mx={mx}\n            my={my}\n            screenX={screenX}\n            screenY={screenY}\n            scaleValue={scaleValue}\n            view={view}\n            tiltGain={tiltGain}\n            lift={lift}\n            ringOpacity={ringOpacity}\n            radius={radius}\n          />\n        ) : null}\n      </div>\n    </section>\n  )\n}\n","target":"components/ui/kanban-list.tsx"}],"dependencies":["motion","react-dom"]}