Dragging an appointment to an empty day in the planner placed it at position 21 instead of position 1. The day looked empty, but SortableJS disagreed.

The Problem

Each day column had a single container with both appointment cards and empty time-slot rows (for click-to-create):

<div class="day-container" data-date="2026-03-25">
    <!-- Appointment cards (draggable) -->
    <div class="appointment" data-id="45">Team standup</div>

    <!-- 20 empty input rows (not draggable, but in the same container) -->
    <div class="time-slot-row">8:00 AM</div>
    <div class="time-slot-row">8:30 AM</div>
    <!-- ... 18 more ... -->
</div>

SortableJS treats the entire container as its sortable area. When I dropped an item into an "empty" day, SortableJS placed it after all 20 time-slot rows -- position 21.

The Fix

Separate the HTML into two containers. SortableJS only sees the one with draggable items:

<div class="day-column" data-date="2026-03-25">
    <!-- SortableJS container: ONLY draggable items -->
    <div class="appointments-container">
        <div class="appointment" data-id="45">Team standup</div>
    </div>

    <!-- Completely separate: not visible to SortableJS -->
    <div class="time-slots-container">
        <div class="time-slot-row">8:00 AM</div>
        <!-- ... -->
    </div>
</div>
new Sortable(document.querySelector('.appointments-container'), {
    group: 'appointments',
    draggable: '.appointment',
    // Now only counts actual appointments, not time-slot rows
});

Items dropped into an empty day now land at position 1. SortableJS counts what it can see -- make sure it only sees what's draggable.