Collision detection root cause:
pointerWithin returns ALL droppables containing the pointer, in
registration order — not sorted by element size. Rack columns register
via useSortable before their child RackSlots, so they always came first
in the result list. over.data.current was { dragType: 'rack' }, never
{ dropType: 'slot' }, so handleDragEnd's slot check never matched and
the module snapped back.
Fix: filter droppableContainers to elements with data.current.dropType
=== 'slot' before running pointerWithin. This does an exact pointer
hit-test against only the 44px slot rects. If no slot is hit (e.g. the
pointer is in a gap or over a rack header), fall back to closestCenter
over all droppables so rack-column reorder still works.
Width fix:
24 ports * 10px + 23 gaps * 3px = 309px
+ px-2 padding (16px) + border-l-4 (4px) = 329px minimum
w-80 (320px) was 9px short, clipping port 24.
Increased to w-96 (384px) / min-w-[384px] — 55px of breathing room.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>