<!-- source-hash: 1bf9b2d5d2d477b1115c900de71defaa -->
Renders a single kanban board column with drag-and-drop support, collapsible layout, infinite scroll via IntersectionObserver, and ticket card rendering.

## Key Components

| Export | Type | Description |
|--------|------|-------------|
| `BoardColumn` | Component | Main column shell handling collapsed/expanded state, border joining, and color tinting |
| `BoardColumnProps` | Interface | Public API for the column component |
| `ColumnBody` | Internal Component | Scrollable droppable zone with `SortableContext`, infinite scroll sentinel, and loading states |
| `SkeletonStack` | Internal Component | Renders `n` skeleton placeholders during initial load |
| `EmptyState` | Internal Component | Illustrated empty state shown when a column has no tickets |

## Usage Example

```typescript
<BoardColumn
  column={{
    id: 'open',
    label: 'Open',
    color: '#3B82F6',
    tickets: myTickets,
    hasMore: true,
    isLoading: false,
    isLoadingMore: false,
  }}
  collapsed={false}
  onToggleCollapse={() => setCollapsed(c => !c)}
  onAddTicket={(columnId) => openNewTicketModal(columnId)}
  getTicketHref={(ticketId) => `/tickets/${ticketId}`}
  renderAssignSlot={(ticket) => <AssigneePicker ticket={ticket} />}
  onLoadMore={(columnId) => fetchNextPage(columnId)}
  joinLeft={false}
  joinRight={true}
/>
```

## Notes

- **Drag-and-drop**: Uses `@dnd-kit/core` (`useDroppable`) and `@dnd-kit/sortable` (`SortableContext`) — drop target is disabled when `column.dropDisabled` is set.
- **Infinite scroll**: An `IntersectionObserver` watches a 1px sentinel div at the bottom of the scroll container; `onLoadMore` fires when it enters the viewport. Scroll is paused while `isLoadingMore` is true.
- **Collapsed state**: When `collapsed=true`, the column shrinks to `w-14` and hides the body; the header remains visible.
- **Joined borders**: `joinLeft`/`joinRight` props remove border radii and borders on adjacent edges for seamless multi-column layouts.