"use client";

import {
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
  type PointerEvent as ReactPointerEvent,
  type TouchEvent as ReactTouchEvent
} from "react";
import { mdiResizeBottomRight } from "@mdi/js";
import { ArrowDown, ArrowUp, ChevronDown, ChevronRight, LaptopMinimalCheck } from "lucide-react";

import type { RentalBooking, TimelineGroup } from "@rental/shared";
import {
  addDays,
  bookingConflictOnDay,
  bookingIntervalsOverlap,
  getBookingEndStamp,
  getBookingStartStamp
} from "@rental/shared";

import { Badge } from "../ui/badge";
import { cn } from "../../lib/cn";

type BookingWithContext = RentalBooking & {
  itemName: string;
  categoryName: string;
};

type SelectionDraft = {
  startRow: number;
  endRow: number;
  startDay: number;
  endDay: number;
};

type MoveBookingInteractionDraft = {
  kind: "move";
  booking: BookingWithContext;
  equipmentItemId: string;
  startDate: string;
  endDate: string;
  pointerStartDay: number;
};

type MoveProjectBookingInteractionDraft = {
  kind: "move-project";
  booking: BookingWithContext;
  bookingIds: string[];
  startDate: string;
  endDate: string;
  startRow: number;
  endRow: number;
  initialStartRow: number;
  initialEndRow: number;
  pointerStartDay: number;
  rowPointerOffset: number;
};

type ResizeEndBookingInteractionDraft = {
  kind: "resize-end";
  booking: BookingWithContext;
  equipmentItemId: string;
  startDate: string;
  endDate: string;
  pointerStartDay: number;
};

type ResizeEndCornerBookingInteractionDraft = {
  kind: "resize-end-corner";
  booking: BookingWithContext;
  bookingIds: string[];
  equipmentItemId: string;
  startDate: string;
  endDate: string;
  startRow: number;
  endRow: number;
  initialStartRow: number;
  initialEndRow: number;
  pointerStartDay: number;
  allowHorizontalResize: boolean;
};

type ResizeStartCornerBookingInteractionDraft = {
  kind: "resize-start-corner";
  booking: BookingWithContext;
  bookingIds: string[];
  equipmentItemId: string;
  startDate: string;
  endDate: string;
  startRow: number;
  endRow: number;
  initialStartRow: number;
  initialEndRow: number;
  pointerStartDay: number;
  allowHorizontalResize: boolean;
};

type ResizeVerticalBookingInteractionDraft = {
  kind: "resize-vertical";
  booking: BookingWithContext;
  startRow: number;
  endRow: number;
  initialStartRow: number;
  initialEndRow: number;
  direction: "top" | "bottom";
};

type BookingInteractionDraft =
  | MoveBookingInteractionDraft
  | MoveProjectBookingInteractionDraft
  | ResizeEndBookingInteractionDraft
  | ResizeStartCornerBookingInteractionDraft
  | ResizeEndCornerBookingInteractionDraft
  | ResizeVerticalBookingInteractionDraft;

type BookingPreviewDraft = {
  kind: "move" | "resize-end" | "resize-vertical";
  booking: BookingWithContext;
  equipmentItemId: string;
  startDate: string;
  endDate: string;
};

type VisibleItem = TimelineGroup["items"][number];
type RowBookingLayout = ReturnType<typeof buildRowBookingLayout>;

type RowRenderState = {
  item: VisibleItem;
  rowIndex: number;
  previewOnRow: boolean;
  renderedBookings: BookingWithContext[];
  rowLayout: RowBookingLayout;
  hasStackedLanes: boolean;
  bookingBarHeight: number;
  bookingTopOffset: number;
  laneStep: number;
  rowMinHeight: number;
};

type MergedBookingBlock = {
  blockId: string;
  topRowIndex: number;
  bottomRowIndex: number;
  representative: BookingWithContext;
  bookingIds: string[];
  equipmentItemIds: string[];
  left: number;
  width: number;
  top: number;
  height: number;
};

type MobileBookingActionMenu = {
  x: number;
  y: number;
  booking: BookingWithContext;
  bookingIds: string[];
};

type MobileMoveDraft = {
  booking: BookingWithContext;
  bookingIds: string[];
  sourceStartRow: number;
  sourceEndRow: number;
  sourceStartDate: string;
  sourceEndDate: string;
  rowSpan: number;
  daySpan: number;
  targetRow: number;
  targetDay: number;
};

type NativeSelectionStyleSnapshot = {
  bodyUserSelect: string;
  bodyWebkitTouchCallout: string;
  bodyWebkitUserSelect: string;
  htmlUserSelect: string;
  htmlWebkitTouchCallout: string;
  htmlWebkitUserSelect: string;
};

type VerticalResizePreviewBlock = {
  bookingId: string;
  bookingIds: string[];
  topRowIndex: number;
  bottomRowIndex: number;
  left: number;
  width: number;
  top: number;
  height: number;
  customerName: string;
};

const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max);

const dayOffset = (from: string, to: string) => {
  const start = new Date(`${from}T12:00:00.000Z`).getTime();
  const end = new Date(`${to}T12:00:00.000Z`).getTime();
  return Math.round((end - start) / 86_400_000);
};

const isDateInsideBooking = (date: string, booking: RentalBooking) => booking.startDate <= date && booking.endDate >= date;

const normalizeSelection = (selection: SelectionDraft) => ({
  startRow: Math.min(selection.startRow, selection.endRow),
  endRow: Math.max(selection.startRow, selection.endRow),
  startDay: Math.min(selection.startDay, selection.endDay),
  endDay: Math.max(selection.startDay, selection.endDay)
});

const getBookingPreviewDraft = (
  booking: BookingWithContext,
  interaction: BookingInteractionDraft | null
): BookingPreviewDraft | null => {
  if (!interaction || interaction.booking.id !== booking.id) {
    return null;
  }

  if (interaction.kind === "resize-vertical") {
    return {
      kind: interaction.kind,
      booking,
      equipmentItemId: booking.equipmentItemId,
      startDate: booking.startDate,
      endDate: booking.endDate
    };
  }

  if (interaction.kind === "move-project") {
    return null;
  }

  if (
    (interaction.kind === "resize-end-corner" || interaction.kind === "resize-start-corner") &&
    interaction.bookingIds.length > 1
  ) {
    return null;
  }

  return {
    kind:
      interaction.kind === "resize-end-corner" || interaction.kind === "resize-start-corner"
        ? "resize-end"
        : interaction.kind,
    booking,
    equipmentItemId: interaction.equipmentItemId,
    startDate: interaction.startDate,
    endDate: interaction.endDate
  };
};

const compareBookingsByStart = (left: BookingWithContext, right: BookingWithContext) =>
  getBookingStartStamp(left) - getBookingStartStamp(right) || getBookingEndStamp(left) - getBookingEndStamp(right);

const buildRowBookingLayout = (bookings: BookingWithContext[]) => {
  const sortedBookings = [...bookings].sort(compareBookingsByStart);
  const laneByBookingId = new Map<string, number>();
  const laneEndStamps: number[] = [];
  const conflictDays = new Set<string>();
  const conflictBookingIds = new Set<string>();
  let maxLane = 0;

  for (const booking of sortedBookings) {
    const bookingStart = getBookingStartStamp(booking);
    const bookingEnd = getBookingEndStamp(booking);
    let laneIndex = laneEndStamps.findIndex((laneEndStamp) => laneEndStamp <= bookingStart);

    if (laneIndex === -1) {
      laneIndex = laneEndStamps.length;
      laneEndStamps.push(bookingEnd);
    } else {
      laneEndStamps[laneIndex] = bookingEnd;
    }

    laneByBookingId.set(booking.id, laneIndex);
    maxLane = Math.max(maxLane, laneIndex);
  }

  for (let leftIndex = 0; leftIndex < sortedBookings.length; leftIndex += 1) {
    const leftBooking = sortedBookings[leftIndex];

    if (!leftBooking) {
      continue;
    }

    for (let rightIndex = leftIndex + 1; rightIndex < sortedBookings.length; rightIndex += 1) {
      const rightBooking = sortedBookings[rightIndex];

      if (!rightBooking) {
        continue;
      }

      if (getBookingStartStamp(rightBooking) >= getBookingEndStamp(leftBooking)) {
        break;
      }

      if (!bookingIntervalsOverlap(leftBooking, rightBooking)) {
        continue;
      }

      conflictBookingIds.add(leftBooking.id);
      conflictBookingIds.add(rightBooking.id);

      let dayCursor = leftBooking.startDate > rightBooking.startDate ? leftBooking.startDate : rightBooking.startDate;
      const dayEnd = leftBooking.endDate < rightBooking.endDate ? leftBooking.endDate : rightBooking.endDate;

      while (dayCursor <= dayEnd) {
        if (bookingConflictOnDay(leftBooking, rightBooking, dayCursor)) {
          conflictDays.add(dayCursor);
        }

        dayCursor = addDays(dayCursor, 1);
      }
    }
  }

  return {
    laneByBookingId,
    maxLane,
    conflictDays,
    conflictBookingIds
  };
};

const getBookingMergeSignature = (booking: BookingWithContext) => {
  if (booking.relationGroupKey?.trim()) {
    return [
      "relation-group",
      booking.relationGroupKey.trim().toLowerCase(),
      booking.startDate,
      booking.endDate,
      booking.startTime ?? "",
      booking.endTime ?? ""
    ].join("::");
  }

  const normalizedProjectName = booking.projectName?.trim().toLowerCase() ?? "";
  const normalizedProjectNumber = booking.projectNumber?.trim().toLowerCase() ?? "";

  if (normalizedProjectNumber) {
    return [
      "project-number",
      normalizedProjectNumber,
      booking.startDate,
      booking.endDate,
      booking.startTime ?? "",
      booking.endTime ?? ""
    ].join("::");
  }

  if (normalizedProjectName) {
    return [
      "project-name",
      normalizedProjectName,
      booking.startDate,
      booking.endDate,
      booking.startTime ?? "",
      booking.endTime ?? ""
    ].join("::");
  }

  return `booking::${booking.id}`;
};

const monthFormatter = new Intl.DateTimeFormat("pl-PL", { month: "long" });

const capitalize = (value: string) => (value ? value.charAt(0).toUpperCase() + value.slice(1) : value);

const buildMonthSegments = (days: string[]) => {
  const segments: Array<{ label: string; startIndex: number; length: number }> = [];

  for (const [index, day] of days.entries()) {
    const label = capitalize(monthFormatter.format(new Date(`${day}T12:00:00.000Z`)));
    const previous = segments[segments.length - 1];

    if (previous && previous.label === label) {
      previous.length += 1;
      continue;
    }

    segments.push({
      label,
      startIndex: index,
      length: 1
    });
  }

  return segments;
};

const buildMergedBookingBlocks = ({
  dayCount,
  effectiveDayWidth,
  firstDay,
  labelWidth,
  rowStates
}: {
  dayCount: number;
  effectiveDayWidth: number;
  firstDay: string;
  labelWidth: number;
  rowStates: RowRenderState[];
}) => {
  const candidatesByRow = rowStates.map((rowState) => {
    const rowCandidates = new Map<
      string,
      {
        booking: BookingWithContext;
        endIndex: number;
        signature: string;
        startIndex: number;
      }
    >();

    if (rowState.hasStackedLanes) {
      return rowCandidates;
    }

    for (const booking of rowState.renderedBookings) {
      const laneIndex = rowState.rowLayout.laneByBookingId.get(booking.id) ?? 0;

      if (laneIndex !== 0 || rowState.rowLayout.conflictBookingIds.has(booking.id)) {
        continue;
      }

      const startIndex = Math.max(0, dayOffset(firstDay, booking.startDate));
      const endIndex = Math.min(dayCount - 1, dayOffset(firstDay, booking.endDate));

      if (endIndex < 0 || startIndex > dayCount - 1) {
        continue;
      }

      const signature = getBookingMergeSignature(booking);

      if (!rowCandidates.has(signature)) {
        rowCandidates.set(signature, {
          booking,
          endIndex,
          signature,
          startIndex
        });
      }
    }

    return rowCandidates;
  });

  const mergedBlocksByTopRowIndex = new Map<number, MergedBookingBlock[]>();
  const mergedBlocksByBottomRowIndex = new Map<number, MergedBookingBlock[]>();
  const mergedBlockByBookingId = new Map<string, MergedBookingBlock>();
  const consumedBookingIds = new Set<string>();

  for (const [rowIndex, rowCandidates] of candidatesByRow.entries()) {
    for (const candidate of rowCandidates.values()) {
      if (consumedBookingIds.has(candidate.booking.id)) {
        continue;
      }

      let bottomRowIndex = rowIndex;
      const bookingIds = [candidate.booking.id];

      for (let nextRowIndex = rowIndex + 1; nextRowIndex < candidatesByRow.length; nextRowIndex += 1) {
        const nextCandidate = candidatesByRow[nextRowIndex]?.get(candidate.signature);

        if (!nextCandidate || consumedBookingIds.has(nextCandidate.booking.id)) {
          break;
        }

        bottomRowIndex = nextRowIndex;
        bookingIds.push(nextCandidate.booking.id);
      }

      if (bottomRowIndex === rowIndex) {
        continue;
      }

      for (const bookingId of bookingIds) {
        consumedBookingIds.add(bookingId);
      }

      const topOffset = rowStates[rowIndex]?.bookingTopOffset ?? 0;
      const spannedHeight = rowStates
        .slice(rowIndex, bottomRowIndex + 1)
        .reduce((height, rowState) => height + rowState.rowMinHeight, 0);
      const block: MergedBookingBlock = {
        blockId: `${candidate.signature}-${rowIndex}`,
        topRowIndex: rowIndex,
        bottomRowIndex,
        representative: candidate.booking,
        bookingIds,
        equipmentItemIds: rowStates.slice(rowIndex, bottomRowIndex + 1).map((rowState) => rowState.item.id),
        left: labelWidth + candidate.startIndex * effectiveDayWidth + 3,
        width: Math.max((candidate.endIndex - candidate.startIndex + 1) * effectiveDayWidth - 6, 18),
        top: topOffset,
        height: Math.max(spannedHeight - 1, 12)
      };

      for (const bookingId of bookingIds) {
        mergedBlockByBookingId.set(bookingId, block);
      }

      const blocks = mergedBlocksByTopRowIndex.get(rowIndex) ?? [];
      blocks.push(block);
      mergedBlocksByTopRowIndex.set(rowIndex, blocks);

      const bottomBlocks = mergedBlocksByBottomRowIndex.get(bottomRowIndex) ?? [];
      bottomBlocks.push(block);
      mergedBlocksByBottomRowIndex.set(bottomRowIndex, bottomBlocks);
    }
  }

  return {
    mergedBlockByBookingId,
    mergedBlocksByBottomRowIndex,
    mergedBlocksByTopRowIndex
  };
};

const CornerResizeMarker = ({ corner }: { corner: "top-left" | "bottom-right" }) => (
  <span className="pointer-events-none absolute inset-0 flex items-center justify-center">
    <svg
      aria-hidden="true"
      className={cn("h-[14px] w-[14px] text-black/90 drop-shadow-[0_1px_1px_rgba(255,255,255,0.18)]", corner === "top-left" && "rotate-180")}
      fill="currentColor"
      viewBox="0 0 24 24"
    >
      <path d={mdiResizeBottomRight} />
    </svg>
  </span>
);

export const TimelineGrid = ({
  dayWidth,
  days,
  groups,
  labelWidth,
  activeSelection,
  collapsedGroups,
  mobileMode,
  rowHeight,
  selectionEnabled,
  interactionsLocked = false,
  suppressConflictIndicators = false,
  onLabelWidthChange,
  onToggleGroup,
  onMoveGroup,
  onSelectionComplete,
  onRequestFutureRange,
  onBookingClick,
  onBookingCopy,
  onCopyDrop,
  copyPreview,
  onBookingQuickUpdate,
  onBookingScopeUpdate,
  onBookingScaleUpdate
}: {
  dayWidth: number;
  days: string[];
  groups: TimelineGroup[];
  labelWidth: number;
  activeSelection?: { equipmentItemIds: string[]; startDate: string; endDate: string } | null;
  collapsedGroups: string[];
  mobileMode: boolean;
  rowHeight: number;
  selectionEnabled: boolean;
  interactionsLocked?: boolean;
  suppressConflictIndicators?: boolean;
  onLabelWidthChange?: (width: number) => void;
  onToggleGroup: (categoryId: string) => void;
  onMoveGroup?: (categoryId: string, direction: -1 | 1) => void;
  onSelectionComplete: (selection: { equipmentItemIds: string[]; startDate: string; endDate: string }) => void;
  onRequestFutureRange?: () => void;
  onBookingClick: (booking: BookingWithContext, bookingIds: string[]) => void;
  onBookingCopy?: (booking: BookingWithContext, bookingIds: string[]) => void;
  onCopyDrop?: (target: { equipmentItemIds: string[]; startDate: string; endDate: string; requestedItemCount: number }) => void;
  copyPreview?: {
    customerName: string;
    rowSpan: number;
    daySpan: number;
  } | null;
  onBookingQuickUpdate: (
    booking: BookingWithContext,
    payload: { equipmentItemId: string; startDate: string; endDate: string }
  ) => Promise<void>;
  onBookingScopeUpdate: (
    booking: BookingWithContext,
    payload: { equipmentItemIds: string[]; scopeBookingIds: string[] }
  ) => Promise<void>;
  onBookingScaleUpdate: (
    booking: BookingWithContext,
    payload: { equipmentItemIds: string[]; scopeBookingIds: string[]; startDate: string; endDate: string }
  ) => Promise<void>;
}) => {
  const [selectionDraft, setSelectionDraft] = useState<SelectionDraft | null>(null);
  const [bookingInteraction, setBookingInteraction] = useState<BookingInteractionDraft | null>(null);
  const [hoveredBookingId, setHoveredBookingId] = useState<string | null>(null);
  const [hoveredMergedBlockId, setHoveredMergedBlockId] = useState<string | null>(null);
  const [scrollerWidth, setScrollerWidth] = useState(0);
  const [labelWidthDraft, setLabelWidthDraft] = useState<number | null>(null);
  const [labelResizing, setLabelResizing] = useState(false);
  const [copyHoverTarget, setCopyHoverTarget] = useState<{ rowIndex: number; dayIndex: number } | null>(null);
  const [mobileActionMenu, setMobileActionMenu] = useState<MobileBookingActionMenu | null>(null);
  const [mobileMoveDraft, setMobileMoveDraft] = useState<MobileMoveDraft | null>(null);

  const scrollerRef = useRef<HTMLDivElement | null>(null);
  const rowElementsRef = useRef(new Map<string, HTMLDivElement>());
  const selectionDraftRef = useRef<SelectionDraft | null>(null);
  const bookingInteractionRef = useRef<BookingInteractionDraft | null>(null);
  const interactionMovedRef = useRef(false);
  const interactionStartPointRef = useRef<{ x: number; y: number } | null>(null);
  const scrollPositionRef = useRef({ left: 0, top: 0 });
  const previousScrollPositionRef = useRef({ left: 0, top: 0 });
  const visibleItemsRef = useRef<VisibleItem[]>([]);
  const daysRef = useRef(days);
  const lastForwardRangeRequestRef = useRef<string | null>(null);
  const labelResizeStateRef = useRef<{ startX: number; startWidth: number; currentWidth: number } | null>(null);
  const copyHoverTargetRef = useRef<{ rowIndex: number; dayIndex: number } | null>(null);
  const pendingCopyHoverTargetRef = useRef<{ rowIndex: number; dayIndex: number } | null>(null);
  const copyHoverFrameRef = useRef<number | null>(null);
  const mobileLongPressTimerRef = useRef<number | null>(null);
  const mobileLongPressStartRef = useRef<{ x: number; y: number } | null>(null);
  const mobileLongPressMovedRef = useRef(false);
  const mobileLongPressTriggeredRef = useRef(false);
  const nativeSelectionStyleRef = useRef<NativeSelectionStyleSnapshot | null>(null);
  const mobileMoveDraftRef = useRef<MobileMoveDraft | null>(null);
  const mobileDropTimerRef = useRef<number | null>(null);
  const mobileDropStartRef = useRef<{ x: number; y: number } | null>(null);

  const visibleItems: VisibleItem[] = [];

  for (const group of groups) {
    if (collapsedGroups.includes(group.categoryId)) {
      continue;
    }

    visibleItems.push(...group.items);
  }

  useEffect(() => {
    selectionDraftRef.current = selectionDraft;
  }, [selectionDraft]);

  useEffect(() => {
    bookingInteractionRef.current = bookingInteraction;
  }, [bookingInteraction]);

  useEffect(() => {
    visibleItemsRef.current = visibleItems;
  }, [visibleItems]);

  useEffect(() => {
    if (!copyPreview) {
      setCopyHoverTarget(null);
    }
  }, [copyPreview]);

  useEffect(() => {
    copyHoverTargetRef.current = copyHoverTarget;
  }, [copyHoverTarget]);

  useEffect(() => {
    mobileMoveDraftRef.current = mobileMoveDraft;
  }, [mobileMoveDraft]);

  useEffect(() => {
    return () => {
      if (copyHoverFrameRef.current !== null) {
        window.cancelAnimationFrame(copyHoverFrameRef.current);
      }

      if (mobileLongPressTimerRef.current !== null) {
        window.clearTimeout(mobileLongPressTimerRef.current);
      }

      if (mobileDropTimerRef.current !== null) {
        window.clearTimeout(mobileDropTimerRef.current);
      }

      const snapshot = nativeSelectionStyleRef.current;

      if (snapshot) {
        document.body.style.userSelect = snapshot.bodyUserSelect;
        document.body.style.setProperty("-webkit-touch-callout", snapshot.bodyWebkitTouchCallout);
        document.body.style.setProperty("-webkit-user-select", snapshot.bodyWebkitUserSelect);
        document.documentElement.style.userSelect = snapshot.htmlUserSelect;
        document.documentElement.style.setProperty("-webkit-touch-callout", snapshot.htmlWebkitTouchCallout);
        document.documentElement.style.setProperty("-webkit-user-select", snapshot.htmlWebkitUserSelect);
        nativeSelectionStyleRef.current = null;
      }
    };
  }, []);

  useEffect(() => {
    daysRef.current = days;
  }, [days]);

  useEffect(() => {
    const lastDay = days[days.length - 1] ?? null;

    if (!lastDay) {
      lastForwardRangeRequestRef.current = null;
      return;
    }

    if (lastForwardRangeRequestRef.current && lastForwardRangeRequestRef.current < lastDay) {
      lastForwardRangeRequestRef.current = null;
    }
  }, [days]);

  useEffect(() => {
    const scroller = scrollerRef.current;

    if (!scroller || typeof ResizeObserver === "undefined") {
      return;
    }

    const updateWidth = () => setScrollerWidth(scroller.clientWidth);
    updateWidth();

    const observer = new ResizeObserver(() => updateWidth());
    observer.observe(scroller);

    return () => observer.disconnect();
  }, []);

  const effectiveLabelWidth = labelWidthDraft ?? labelWidth;
  const fittedDesktopDayWidth =
    !mobileMode && scrollerWidth > effectiveLabelWidth ? Math.floor((scrollerWidth - effectiveLabelWidth) / 30) : 34;
  const effectiveDayWidth = mobileMode ? dayWidth : clamp(Math.min(dayWidth, fittedDesktopDayWidth), 26, 64);
  const effectiveRowHeight = rowHeight;
  const uniformBookingBarHeight = Math.max(effectiveRowHeight - 1, 12);
  const uniformBookingTopOffset = 0;
  const stackedLaneGap = 3;
  const gridTemplateColumns = `${effectiveLabelWidth}px repeat(${days.length}, ${effectiveDayWidth}px)`;
  const today = new Date().toISOString().slice(0, 10);
  const firstDay = days[0];
  const lastDay = days[days.length - 1];
  const scrollerMaxHeight = mobileMode ? "min(68dvh, 760px)" : "min(176dvh, 2360px)";
  const bookingCornerHandleSize = mobileMode ? 18 : 16;
  const bookingCornerHandleTranslate = mobileMode ? 18 : 14;
  const bookingHandleOffset = mobileMode ? -6 : -5;
  const bookingHandleClassName = "absolute z-30 flex cursor-pointer items-center justify-center touch-none opacity-100";
  const activeBookingId = bookingInteraction?.booking.id ?? null;

  useEffect(() => {
    if (!labelResizing) {
      setLabelWidthDraft(null);
    }
  }, [labelResizing]);

  useEffect(() => {
    if (!labelResizing) {
      return;
    }

    const previousCursor = document.body.style.cursor;
    const previousUserSelect = document.body.style.userSelect;
    document.body.style.cursor = "col-resize";
    document.body.style.userSelect = "none";

    const minLabelWidth = mobileMode ? 132 : 150;
    const maxLabelWidth = mobileMode ? 240 : 320;

    const handlePointerMove = (event: PointerEvent) => {
      const state = labelResizeStateRef.current;

      if (!state) {
        return;
      }

      const nextWidth = clamp(state.startWidth + (event.clientX - state.startX), minLabelWidth, maxLabelWidth);
      state.currentWidth = nextWidth;
      setLabelWidthDraft(nextWidth);
    };

    const finishResize = () => {
      const state = labelResizeStateRef.current;

      setLabelResizing(false);
      labelResizeStateRef.current = null;

      if (state && onLabelWidthChange && Math.abs(state.currentWidth - labelWidth) >= 1) {
        onLabelWidthChange(state.currentWidth);
      }

      document.body.style.cursor = previousCursor;
      document.body.style.userSelect = previousUserSelect;
    };

    window.addEventListener("pointermove", handlePointerMove);
    window.addEventListener("pointerup", finishResize);
    window.addEventListener("pointercancel", finishResize);

    return () => {
      window.removeEventListener("pointermove", handlePointerMove);
      window.removeEventListener("pointerup", finishResize);
      window.removeEventListener("pointercancel", finishResize);
      document.body.style.cursor = previousCursor;
      document.body.style.userSelect = previousUserSelect;
    };
  }, [labelResizing, labelWidth, mobileMode, onLabelWidthChange]);

  useLayoutEffect(() => {
    const scroller = scrollerRef.current;

    if (!scroller) {
      return;
    }

    const maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth);
    const maxScrollTop = Math.max(0, scroller.scrollHeight - scroller.clientHeight);
    const nextScrollLeft = clamp(scrollPositionRef.current.left, 0, maxScrollLeft);
    const nextScrollTop = clamp(scrollPositionRef.current.top, 0, maxScrollTop);

    if (Math.abs(scroller.scrollLeft - nextScrollLeft) > 1) {
      scroller.scrollLeft = nextScrollLeft;
    }

    if (Math.abs(scroller.scrollTop - nextScrollTop) > 1) {
      scroller.scrollTop = nextScrollTop;
    }
  }, [collapsedGroups, days.length, effectiveLabelWidth, groups, mobileMode, rowHeight, scrollerWidth]);

  useEffect(() => {
    if (mobileMode || !onRequestFutureRange || interactionsLocked) {
      return;
    }

    const scroller = scrollerRef.current;
    const currentLastDay = daysRef.current[daysRef.current.length - 1];

    if (!scroller || !currentLastDay) {
      return;
    }

    const remainingRight = scroller.scrollWidth - scroller.clientWidth - scroller.scrollLeft;
    const threshold = Math.max(effectiveDayWidth * 4, 120);

    if (remainingRight > threshold || lastForwardRangeRequestRef.current === currentLastDay) {
      return;
    }

    lastForwardRangeRequestRef.current = currentLastDay;
    onRequestFutureRange();
  }, [days.length, effectiveDayWidth, effectiveLabelWidth, interactionsLocked, mobileMode, onRequestFutureRange, scrollerWidth]);

  if (!firstDay) {
    return null;
  }

  const setRowElement = (itemId: string, element: HTMLDivElement | null) => {
    if (element) {
      rowElementsRef.current.set(itemId, element);
      return;
    }

    rowElementsRef.current.delete(itemId);
  };

  const updateCopyHoverTarget = (target: { rowIndex: number; dayIndex: number } | null) => {
    if (!target) {
      return;
    }

    pendingCopyHoverTargetRef.current = target;

    if (copyHoverFrameRef.current !== null) {
      return;
    }

    copyHoverFrameRef.current = window.requestAnimationFrame(() => {
      copyHoverFrameRef.current = null;
      const nextTarget = pendingCopyHoverTargetRef.current;
      const currentTarget = copyHoverTargetRef.current;

      if (!nextTarget) {
        return;
      }

      if (
        currentTarget &&
        currentTarget.rowIndex === nextTarget.rowIndex &&
        currentTarget.dayIndex === nextTarget.dayIndex
      ) {
        return;
      }

      setCopyHoverTarget(nextTarget);
    });
  };

  const resolveCopyDropTarget = (rowIndex: number, dayIndex: number) => {
    if (
      selectionPreview &&
      rowIndex >= selectionPreview.startRow &&
      rowIndex <= selectionPreview.endRow &&
      dayIndex >= selectionPreview.startDay &&
      dayIndex <= selectionPreview.endDay
    ) {
      return {
        equipmentItemIds: visibleItems.slice(selectionPreview.startRow, selectionPreview.endRow + 1).map((item) => item.id),
        startDate: days[selectionPreview.startDay] ?? firstDay,
        endDate: days[selectionPreview.endDay] ?? firstDay,
        requestedItemCount: selectionPreview.endRow - selectionPreview.startRow + 1
      };
    }

    const nextEndRow = clamp(
      rowIndex + Math.max(copyPreview?.rowSpan ?? 1, 1) - 1,
      rowIndex,
      Math.max(visibleItems.length - 1, rowIndex)
    );
    const nextEndDay = clamp(
      dayIndex + Math.max(copyPreview?.daySpan ?? 1, 1) - 1,
      dayIndex,
      Math.max(days.length - 1, dayIndex)
    );

    return {
      equipmentItemIds: visibleItems.slice(rowIndex, nextEndRow + 1).map((item) => item.id),
      startDate: days[dayIndex] ?? firstDay,
      endDate: days[nextEndDay] ?? firstDay,
      requestedItemCount: Math.max(copyPreview?.rowSpan ?? 1, 1)
    };
  };

  const updateSelectionTarget = (target: { rowIndex: number; dayIndex: number }) => {
    setSelectionDraft((draft) =>
      draft
        ? {
            ...draft,
            endRow: target.rowIndex,
            endDay: target.dayIndex
          }
        : draft
    );
  };

  const autoScrollScroller = (clientX: number, clientY: number) => {
    const scroller = scrollerRef.current;

    if (!scroller) {
      return;
    }

    const rect = scroller.getBoundingClientRect();
    const edge = 56;

    if (clientY < rect.top + edge) {
      scroller.scrollTop -= Math.ceil((rect.top + edge - clientY) / 8);
    } else if (clientY > rect.bottom - edge) {
      scroller.scrollTop += Math.ceil((clientY - (rect.bottom - edge)) / 8);
    }

    if (clientX < rect.left + edge) {
      scroller.scrollLeft -= Math.ceil((rect.left + edge - clientX) / 8);
    } else if (clientX > rect.right - edge) {
      scroller.scrollLeft += Math.ceil((clientX - (rect.right - edge)) / 8);
    }

    scrollPositionRef.current = {
      left: scroller.scrollLeft,
      top: scroller.scrollTop
    };
  };

  const getDayIndexFromClientX = (clientX: number) => {
    const scroller = scrollerRef.current;
    const currentDays = daysRef.current;

    if (!scroller || currentDays.length === 0) {
      return null;
    }

    const rect = scroller.getBoundingClientRect();
    const contentX = clientX - rect.left + scroller.scrollLeft - effectiveLabelWidth;

    return clamp(Math.floor(contentX / effectiveDayWidth), 0, currentDays.length - 1);
  };

  const getRowIndexFromClientY = (clientY: number) => {
    const currentVisibleItems = visibleItemsRef.current;

    if (currentVisibleItems.length === 0) {
      return null;
    }

    let closestIndex = 0;
    let closestDistance = Number.POSITIVE_INFINITY;

    for (const [index, item] of currentVisibleItems.entries()) {
      const rowElement = rowElementsRef.current.get(item.id);

      if (!rowElement) {
        continue;
      }

      const rect = rowElement.getBoundingClientRect();

      if (clientY >= rect.top && clientY <= rect.bottom) {
        return index;
      }

      const distance = clientY < rect.top ? rect.top - clientY : clientY - rect.bottom;

      if (distance < closestDistance) {
        closestDistance = distance;
        closestIndex = index;
      }
    }

    return closestIndex;
  };

  const resolveGridTarget = (clientX: number, clientY: number) => {
    const dayIndex = getDayIndexFromClientX(clientX);
    const rowIndex = getRowIndexFromClientY(clientY);

    if (dayIndex === null || rowIndex === null) {
      return null;
    }

    return { dayIndex, rowIndex };
  };

  const clampMobileMenuPosition = (x: number, y: number) => ({
    x: clamp(x, 10, Math.max(10, window.innerWidth - 190)),
    y: clamp(y, 10, Math.max(10, window.innerHeight - 150))
  });

  const cancelMobileBookingLongPress = () => {
    if (mobileLongPressTimerRef.current !== null) {
      window.clearTimeout(mobileLongPressTimerRef.current);
      mobileLongPressTimerRef.current = null;
    }

    mobileLongPressStartRef.current = null;
  };

  const cancelMobileDropLongPress = () => {
    if (mobileDropTimerRef.current !== null) {
      window.clearTimeout(mobileDropTimerRef.current);
      mobileDropTimerRef.current = null;
    }

    mobileDropStartRef.current = null;
  };

  const lockMobileNativeSelection = () => {
    if (nativeSelectionStyleRef.current) {
      return;
    }

    nativeSelectionStyleRef.current = {
      bodyUserSelect: document.body.style.userSelect,
      bodyWebkitTouchCallout: document.body.style.getPropertyValue("-webkit-touch-callout"),
      bodyWebkitUserSelect: document.body.style.getPropertyValue("-webkit-user-select"),
      htmlUserSelect: document.documentElement.style.userSelect,
      htmlWebkitTouchCallout: document.documentElement.style.getPropertyValue("-webkit-touch-callout"),
      htmlWebkitUserSelect: document.documentElement.style.getPropertyValue("-webkit-user-select")
    };

    document.body.style.userSelect = "none";
    document.body.style.setProperty("-webkit-touch-callout", "none");
    document.body.style.setProperty("-webkit-user-select", "none");
    document.documentElement.style.userSelect = "none";
    document.documentElement.style.setProperty("-webkit-touch-callout", "none");
    document.documentElement.style.setProperty("-webkit-user-select", "none");

    const currentSelection = window.getSelection?.();
    currentSelection?.removeAllRanges();
  };

  const unlockMobileNativeSelection = () => {
    const snapshot = nativeSelectionStyleRef.current;

    if (!snapshot) {
      return;
    }

    document.body.style.userSelect = snapshot.bodyUserSelect;
    document.body.style.setProperty("-webkit-touch-callout", snapshot.bodyWebkitTouchCallout);
    document.body.style.setProperty("-webkit-user-select", snapshot.bodyWebkitUserSelect);
    document.documentElement.style.userSelect = snapshot.htmlUserSelect;
    document.documentElement.style.setProperty("-webkit-touch-callout", snapshot.htmlWebkitTouchCallout);
    document.documentElement.style.setProperty("-webkit-user-select", snapshot.htmlWebkitUserSelect);
    nativeSelectionStyleRef.current = null;
  };

  const suppressMobileNativeTouch = (event: ReactTouchEvent<HTMLElement>) => {
    if (!mobileMode) {
      return;
    }

    lockMobileNativeSelection();
    window.getSelection?.()?.removeAllRanges();

    if (event.type !== "touchend" && event.type !== "touchcancel") {
      event.preventDefault();
      event.stopPropagation();
    }
  };

  const openMobileBookingMenu = (clientX: number, clientY: number, booking: BookingWithContext, bookingIds: string[]) => {
    const position = clampMobileMenuPosition(clientX, clientY);

    setMobileActionMenu({
      ...position,
      booking,
      bookingIds
    });
  };

  const setMobileMoveTarget = (target: { rowIndex: number; dayIndex: number }) => {
    setMobileMoveDraft((draft) => {
      if (!draft) {
        return draft;
      }

      return {
        ...draft,
        targetRow: clamp(target.rowIndex, 0, Math.max(visibleItemsRef.current.length - 1, 0)),
        targetDay: clamp(target.dayIndex, 0, Math.max(daysRef.current.length - 1, 0))
      };
    });
  };

  const startMobileMoveMode = (
    booking: BookingWithContext,
    bookingIds: string[],
    sourceStartRow: number,
    sourceEndRow: number
  ) => {
    const normalizedStartRow = Math.min(sourceStartRow, sourceEndRow);
    const normalizedEndRow = Math.max(sourceStartRow, sourceEndRow);
    const sourceStartDay = clamp(dayOffset(firstDay, booking.startDate), 0, Math.max(days.length - 1, 0));
    const sourceEndDay = clamp(dayOffset(firstDay, booking.endDate), 0, Math.max(days.length - 1, 0));

    setSelectionDraft(null);
    setBookingInteraction(null);
    setMobileActionMenu(null);
    setMobileMoveDraft({
      booking,
      bookingIds,
      sourceStartRow: normalizedStartRow,
      sourceEndRow: normalizedEndRow,
      sourceStartDate: booking.startDate,
      sourceEndDate: booking.endDate,
      rowSpan: normalizedEndRow - normalizedStartRow + 1,
      daySpan: Math.max(sourceEndDay - sourceStartDay + 1, 1),
      targetRow: normalizedStartRow,
      targetDay: sourceStartDay
    });
  };

  const commitMobileMoveDraft = async () => {
    const draft = mobileMoveDraftRef.current;

    if (!draft) {
      return;
    }

    const targetStartRow = clamp(draft.targetRow, 0, Math.max(visibleItemsRef.current.length - 1, 0));
    const targetEndRow = clamp(targetStartRow + draft.rowSpan - 1, targetStartRow, Math.max(visibleItemsRef.current.length - 1, targetStartRow));
    const equipmentItemIds = visibleItemsRef.current.slice(targetStartRow, targetEndRow + 1).map((item) => item.id);
    const targetStartDate = daysRef.current[draft.targetDay] ?? draft.sourceStartDate;
    const targetEndDate = addDays(targetStartDate, draft.daySpan - 1);

    setMobileMoveDraft(null);
    mobileMoveDraftRef.current = null;
    cancelMobileDropLongPress();
    unlockMobileNativeSelection();

    if (
      targetStartRow === draft.sourceStartRow &&
      targetEndRow === draft.sourceEndRow &&
      targetStartDate === draft.sourceStartDate &&
      targetEndDate === draft.sourceEndDate
    ) {
      return;
    }

    if (draft.bookingIds.length > 1 || draft.rowSpan > 1) {
      await onBookingScaleUpdate(draft.booking, {
        equipmentItemIds: equipmentItemIds.length > 0 ? equipmentItemIds : [draft.booking.equipmentItemId],
        scopeBookingIds: draft.bookingIds,
        startDate: targetStartDate,
        endDate: targetEndDate
      });
      return;
    }

    await onBookingQuickUpdate(draft.booking, {
      equipmentItemId: equipmentItemIds[0] ?? draft.booking.equipmentItemId,
      startDate: targetStartDate,
      endDate: targetEndDate
    });
  };

  const startMobileDropLongPress = (event: ReactPointerEvent<HTMLElement>, target: { rowIndex: number; dayIndex: number }) => {
    if (!mobileMode || event.pointerType !== "touch" || !mobileMoveDraftRef.current) {
      return false;
    }

    event.stopPropagation();
    setMobileMoveTarget(target);
    cancelMobileDropLongPress();
    mobileDropStartRef.current = { x: event.clientX, y: event.clientY };
    mobileDropTimerRef.current = window.setTimeout(() => {
      void commitMobileMoveDraft();
      navigator.vibrate?.(16);
    }, 420);
    return true;
  };

  const updateMobileDropLongPress = (event: ReactPointerEvent<HTMLElement>, target?: { rowIndex: number; dayIndex: number }) => {
    if (!mobileMode || event.pointerType !== "touch" || !mobileMoveDraftRef.current) {
      return;
    }

    if (target) {
      setMobileMoveTarget(target);
    }

    if (!mobileDropStartRef.current) {
      return;
    }

    const movedX = Math.abs(event.clientX - mobileDropStartRef.current.x);
    const movedY = Math.abs(event.clientY - mobileDropStartRef.current.y);

    if (movedX >= 8 || movedY >= 8) {
      cancelMobileDropLongPress();
    }
  };

  const startMobileBookingLongPress = (
    event: ReactPointerEvent<HTMLElement>,
    booking: BookingWithContext,
    bookingIds: string[],
    sourceStartRow: number,
    sourceEndRow: number
  ) => {
    if (!mobileMode || event.pointerType !== "touch") {
      return false;
    }

    event.preventDefault();
    event.stopPropagation();
    event.currentTarget.setPointerCapture?.(event.pointerId);
    lockMobileNativeSelection();
    setMobileActionMenu(null);
    cancelMobileBookingLongPress();

    mobileLongPressStartRef.current = { x: event.clientX, y: event.clientY };
    mobileLongPressMovedRef.current = false;
    mobileLongPressTriggeredRef.current = false;
    mobileLongPressTimerRef.current = window.setTimeout(() => {
      mobileLongPressTimerRef.current = null;
      mobileLongPressTriggeredRef.current = true;
      startMobileMoveMode(booking, bookingIds, sourceStartRow, sourceEndRow);
      navigator.vibrate?.(12);
    }, 300);

    return true;
  };

  const updateMobileBookingLongPress = (event: ReactPointerEvent<HTMLElement>) => {
    if (!mobileMode || event.pointerType !== "touch" || !mobileLongPressStartRef.current) {
      return;
    }

    const movedX = Math.abs(event.clientX - mobileLongPressStartRef.current.x);
    const movedY = Math.abs(event.clientY - mobileLongPressStartRef.current.y);

    if (movedX >= 6 || movedY >= 6) {
      mobileLongPressMovedRef.current = true;
      cancelMobileBookingLongPress();
    }
  };

  const finishMobileBookingTouch = (
    event: ReactPointerEvent<HTMLElement>,
    booking: BookingWithContext,
    bookingIds: string[]
  ) => {
    if (!mobileMode || event.pointerType !== "touch") {
      return false;
    }

    if (mobileMoveDraftRef.current) {
      event.preventDefault();
      event.stopPropagation();
      cancelMobileBookingLongPress();
      cancelMobileDropLongPress();
      mobileLongPressMovedRef.current = false;
      mobileLongPressTriggeredRef.current = false;
      return true;
    }

    const wasTriggered = mobileLongPressTriggeredRef.current;
    const wasMoved = mobileLongPressMovedRef.current;
    const hasActiveBookingInteraction = Boolean(bookingInteractionRef.current);

    if (hasActiveBookingInteraction) {
      cancelMobileBookingLongPress();
      mobileLongPressMovedRef.current = false;
      mobileLongPressTriggeredRef.current = false;
      unlockMobileNativeSelection();
      return false;
    }

    event.preventDefault();
    event.stopPropagation();
    cancelMobileBookingLongPress();

    if (!wasTriggered && !wasMoved) {
      onBookingClick(booking, bookingIds);
    }

    mobileLongPressMovedRef.current = false;
    mobileLongPressTriggeredRef.current = false;
    unlockMobileNativeSelection();
    return true;
  };

  const hasActivePointerInteraction = Boolean(selectionDraft || bookingInteraction);

  useEffect(() => {
    if (!hasActivePointerInteraction) {
      return;
    }

    const handlePointerMove = (event: PointerEvent) => {
      const startPoint = interactionStartPointRef.current;

      if (startPoint && !interactionMovedRef.current) {
        const movedX = Math.abs(event.clientX - startPoint.x);
        const movedY = Math.abs(event.clientY - startPoint.y);

        if (movedX >= 6 || movedY >= 6) {
          interactionMovedRef.current = true;
        }
      }

      autoScrollScroller(event.clientX, event.clientY);

      const target = resolveGridTarget(event.clientX, event.clientY);

      if (!target) {
        return;
      }

      const currentSelection = selectionDraftRef.current;

      if (currentSelection) {
        updateSelectionTarget(target);
        return;
      }

      const currentBookingInteraction = bookingInteractionRef.current;

      if (!currentBookingInteraction) {
        return;
      }

      if (currentBookingInteraction.kind === "move") {
        const nextItem = visibleItemsRef.current[target.rowIndex];

        if (!nextItem) {
          return;
        }

        const dayDelta = target.dayIndex - currentBookingInteraction.pointerStartDay;

        setBookingInteraction((draft) =>
          draft && draft.kind === "move"
            ? {
                ...draft,
                equipmentItemId: nextItem.id,
                startDate: addDays(draft.booking.startDate, dayDelta),
                endDate: addDays(draft.booking.endDate, dayDelta)
              }
            : draft
        );
        return;
      }

      if (currentBookingInteraction.kind === "move-project") {
        const rowSpan = currentBookingInteraction.initialEndRow - currentBookingInteraction.initialStartRow;
        const maxTopRow = Math.max(visibleItemsRef.current.length - rowSpan - 1, 0);
        const nextTopRow = clamp(target.rowIndex - currentBookingInteraction.rowPointerOffset, 0, maxTopRow);
        const dayDelta = target.dayIndex - currentBookingInteraction.pointerStartDay;

        setBookingInteraction((draft) =>
          draft && draft.kind === "move-project"
            ? {
                ...draft,
                startRow: nextTopRow,
                endRow: nextTopRow + rowSpan,
                startDate: addDays(draft.booking.startDate, dayDelta),
                endDate: addDays(draft.booking.endDate, dayDelta)
              }
            : draft
        );
        return;
      }

      if (currentBookingInteraction.kind === "resize-start-corner") {
        const hoveredDay = daysRef.current[target.dayIndex] ?? currentBookingInteraction.startDate;
        const nextStartDate = currentBookingInteraction.allowHorizontalResize
          ? hoveredDay > currentBookingInteraction.endDate
            ? currentBookingInteraction.endDate
            : hoveredDay
          : currentBookingInteraction.startDate;

        setBookingInteraction((draft) =>
          draft && draft.kind === "resize-start-corner"
            ? {
                ...draft,
                startDate: nextStartDate,
                startRow: Math.min(target.rowIndex, draft.endRow)
              }
            : draft
        );
        return;
      }

      if (currentBookingInteraction.kind === "resize-end-corner") {
        const hoveredDay = daysRef.current[target.dayIndex] ?? currentBookingInteraction.endDate;
        const nextEndDate = currentBookingInteraction.allowHorizontalResize
          ? hoveredDay < currentBookingInteraction.startDate
            ? currentBookingInteraction.startDate
            : hoveredDay
          : currentBookingInteraction.endDate;

        setBookingInteraction((draft) =>
          draft && draft.kind === "resize-end-corner"
            ? {
                ...draft,
                endDate: nextEndDate,
                endRow: Math.max(target.rowIndex, draft.startRow)
              }
            : draft
        );
        return;
      }

      if (currentBookingInteraction.kind === "resize-vertical") {
        setBookingInteraction((draft) =>
          draft && draft.kind === "resize-vertical"
            ? {
                ...draft,
                startRow:
                  draft.direction === "top"
                    ? Math.min(target.rowIndex, draft.endRow)
                    : draft.startRow,
                endRow:
                  draft.direction === "bottom"
                    ? Math.max(target.rowIndex, draft.startRow)
                    : draft.endRow
              }
            : draft
        );
        return;
      }

      const hoveredDay = daysRef.current[target.dayIndex] ?? currentBookingInteraction.endDate;
      const nextEndDate = hoveredDay < currentBookingInteraction.booking.startDate
        ? currentBookingInteraction.booking.startDate
        : hoveredDay;

      setBookingInteraction((draft) =>
        draft && draft.kind === "resize-end"
          ? {
              ...draft,
              endDate: nextEndDate
            }
          : draft
      );
    };

    const handlePointerUp = () => {
      const currentSelection = selectionDraftRef.current;

      if (currentSelection) {
        const normalized = normalizeSelection(currentSelection);
        const equipmentItemIds = visibleItemsRef.current
          .slice(normalized.startRow, normalized.endRow + 1)
          .map((item) => item.id);

        setSelectionDraft(null);
        interactionMovedRef.current = false;
        interactionStartPointRef.current = null;

        if (equipmentItemIds.length === 0) {
          return;
        }

        onSelectionComplete({
          equipmentItemIds,
          startDate: daysRef.current[normalized.startDay] ?? firstDay,
          endDate: daysRef.current[normalized.endDay] ?? firstDay
        });
        return;
      }

      const currentBookingInteraction = bookingInteractionRef.current;

      if (!currentBookingInteraction) {
        interactionMovedRef.current = false;
        interactionStartPointRef.current = null;
        return;
      }

      interactionStartPointRef.current = null;

      if (currentBookingInteraction.kind === "move-project") {
        const startRow = Math.min(currentBookingInteraction.startRow, currentBookingInteraction.endRow);
        const endRow = Math.max(currentBookingInteraction.startRow, currentBookingInteraction.endRow);
        const equipmentItemIds = visibleItemsRef.current.slice(startRow, endRow + 1).map((item) => item.id);
        const rowsChanged =
          startRow !== currentBookingInteraction.initialStartRow || endRow !== currentBookingInteraction.initialEndRow;
        const datesChanged =
          currentBookingInteraction.startDate !== currentBookingInteraction.booking.startDate ||
          currentBookingInteraction.endDate !== currentBookingInteraction.booking.endDate;

        if (!rowsChanged && !datesChanged) {
          setBookingInteraction(null);
          if (!interactionMovedRef.current && !mobileLongPressTriggeredRef.current) {
            onBookingClick(currentBookingInteraction.booking, [currentBookingInteraction.booking.id]);
          }

          interactionMovedRef.current = false;
          mobileLongPressMovedRef.current = false;
          mobileLongPressTriggeredRef.current = false;
          unlockMobileNativeSelection();
          return;
        }

        void onBookingScaleUpdate(currentBookingInteraction.booking, {
          equipmentItemIds: equipmentItemIds.length > 0 ? equipmentItemIds : [currentBookingInteraction.booking.equipmentItemId],
          scopeBookingIds: currentBookingInteraction.bookingIds,
          startDate: currentBookingInteraction.startDate,
          endDate: currentBookingInteraction.endDate
        }).finally(() => {
          setBookingInteraction(null);
          unlockMobileNativeSelection();
        });
        interactionMovedRef.current = false;
        mobileLongPressMovedRef.current = false;
        mobileLongPressTriggeredRef.current = false;
        return;
      }

      if (currentBookingInteraction.kind === "resize-vertical") {
        const startRow = Math.min(
          currentBookingInteraction.startRow,
          currentBookingInteraction.endRow
        );
        const endRow = Math.max(
          currentBookingInteraction.startRow,
          currentBookingInteraction.endRow
        );
        const initialStartRow = currentBookingInteraction.initialStartRow;
        const initialEndRow = currentBookingInteraction.initialEndRow;

        if (startRow === initialStartRow && endRow === initialEndRow) {
          setBookingInteraction(null);
          unlockMobileNativeSelection();
          return;
        }

        const equipmentItemIds = visibleItemsRef.current.slice(startRow, endRow + 1).map((item) => item.id);

        if (equipmentItemIds.length === 0) {
          setBookingInteraction(null);
          unlockMobileNativeSelection();
          return;
        }

        void onBookingScopeUpdate(currentBookingInteraction.booking, {
          equipmentItemIds,
          scopeBookingIds: [currentBookingInteraction.booking.id]
        }).finally(() => {
          setBookingInteraction(null);
          unlockMobileNativeSelection();
        });
        return;
      }

      if (currentBookingInteraction.kind === "resize-end-corner") {
        const startRow = Math.min(currentBookingInteraction.startRow, currentBookingInteraction.endRow);
        const endRow = Math.max(currentBookingInteraction.startRow, currentBookingInteraction.endRow);
        const initialStartRow = currentBookingInteraction.initialStartRow;
        const initialEndRow = currentBookingInteraction.initialEndRow;
        const equipmentItemIds = visibleItemsRef.current.slice(startRow, endRow + 1).map((item) => item.id);
        const rowChanged = startRow !== initialStartRow || endRow !== initialEndRow;
        const dateChanged =
          currentBookingInteraction.startDate !== currentBookingInteraction.booking.startDate ||
          currentBookingInteraction.endDate !== currentBookingInteraction.booking.endDate;

        if (!rowChanged && !dateChanged) {
          setBookingInteraction(null);
          interactionMovedRef.current = false;
          unlockMobileNativeSelection();
          return;
        }

        void onBookingScaleUpdate(currentBookingInteraction.booking, {
          equipmentItemIds: equipmentItemIds.length > 0 ? equipmentItemIds : [currentBookingInteraction.booking.equipmentItemId],
          scopeBookingIds: currentBookingInteraction.bookingIds,
          startDate: currentBookingInteraction.startDate,
          endDate: currentBookingInteraction.endDate
        }).finally(() => {
          setBookingInteraction(null);
          unlockMobileNativeSelection();
        });
        interactionMovedRef.current = false;
        return;
      }

      if (currentBookingInteraction.kind === "resize-start-corner") {
        const startRow = Math.min(currentBookingInteraction.startRow, currentBookingInteraction.endRow);
        const endRow = Math.max(currentBookingInteraction.startRow, currentBookingInteraction.endRow);
        const initialStartRow = currentBookingInteraction.initialStartRow;
        const initialEndRow = currentBookingInteraction.initialEndRow;
        const equipmentItemIds = visibleItemsRef.current.slice(startRow, endRow + 1).map((item) => item.id);
        const rowChanged = startRow !== initialStartRow || endRow !== initialEndRow;
        const dateChanged =
          currentBookingInteraction.startDate !== currentBookingInteraction.booking.startDate ||
          currentBookingInteraction.endDate !== currentBookingInteraction.booking.endDate;

        if (!rowChanged && !dateChanged) {
          setBookingInteraction(null);
          interactionMovedRef.current = false;
          unlockMobileNativeSelection();
          return;
        }

        void onBookingScaleUpdate(currentBookingInteraction.booking, {
          equipmentItemIds: equipmentItemIds.length > 0 ? equipmentItemIds : [currentBookingInteraction.booking.equipmentItemId],
          scopeBookingIds: currentBookingInteraction.bookingIds,
          startDate: currentBookingInteraction.startDate,
          endDate: currentBookingInteraction.endDate
        }).finally(() => {
          setBookingInteraction(null);
          unlockMobileNativeSelection();
        });
        interactionMovedRef.current = false;
        return;
      }

      const changed =
        currentBookingInteraction.equipmentItemId !== currentBookingInteraction.booking.equipmentItemId ||
        currentBookingInteraction.startDate !== currentBookingInteraction.booking.startDate ||
        currentBookingInteraction.endDate !== currentBookingInteraction.booking.endDate;

      if (!changed) {
        setBookingInteraction(null);
        if (currentBookingInteraction.kind === "move" && !interactionMovedRef.current && !mobileLongPressTriggeredRef.current) {
          onBookingClick(currentBookingInteraction.booking, [currentBookingInteraction.booking.id]);
        }

        interactionMovedRef.current = false;
        mobileLongPressMovedRef.current = false;
        mobileLongPressTriggeredRef.current = false;
        unlockMobileNativeSelection();
        return;
      }

      void onBookingQuickUpdate(currentBookingInteraction.booking, {
        equipmentItemId: currentBookingInteraction.equipmentItemId,
        startDate: currentBookingInteraction.startDate,
        endDate: currentBookingInteraction.endDate
      }).finally(() => {
        setBookingInteraction(null);
        unlockMobileNativeSelection();
      });
      interactionMovedRef.current = false;
      mobileLongPressMovedRef.current = false;
      mobileLongPressTriggeredRef.current = false;
    };

    window.addEventListener("pointermove", handlePointerMove);
    window.addEventListener("pointerup", handlePointerUp);
    window.addEventListener("pointercancel", handlePointerUp);

    return () => {
      window.removeEventListener("pointermove", handlePointerMove);
      window.removeEventListener("pointerup", handlePointerUp);
      window.removeEventListener("pointercancel", handlePointerUp);
    };
  }, [
    firstDay,
    hasActivePointerInteraction,
    onBookingClick,
    onBookingQuickUpdate,
    onBookingScaleUpdate,
    onBookingScopeUpdate,
    onSelectionComplete
  ]);

  useEffect(() => {
    if (!selectionDraft) {
      return;
    }

    const previousUserSelect = document.body.style.userSelect;
    document.body.style.userSelect = "none";

    return () => {
      document.body.style.userSelect = previousUserSelect;
    };
  }, [selectionDraft]);

  const maybeRequestFutureRange = (scrollLeftDelta: number) => {
    if (!onRequestFutureRange || interactionsLocked) {
      return;
    }

    const scroller = scrollerRef.current;
    const currentLastDay = daysRef.current[daysRef.current.length - 1];

    if (!scroller || !currentLastDay) {
      return;
    }

    const remainingRight = scroller.scrollWidth - scroller.clientWidth - scroller.scrollLeft;
    const threshold = Math.max(effectiveDayWidth * 5, 150);

    if (scrollLeftDelta <= 0 || remainingRight > threshold) {
      return;
    }

    if (lastForwardRangeRequestRef.current === currentLastDay) {
      return;
    }

    lastForwardRangeRequestRef.current = currentLastDay;
    onRequestFutureRange();
  };

  const selectionPreview = useMemo(() => {
    if (selectionDraft) {
      return normalizeSelection(selectionDraft);
    }

    if (!activeSelection || days.length === 0 || visibleItems.length === 0) {
      return null;
    }

    const selectedRowIndexes = visibleItems
      .map((item, index) => (activeSelection.equipmentItemIds.includes(item.id) ? index : -1))
      .filter((index) => index >= 0);

    if (selectedRowIndexes.length === 0) {
      return null;
    }

    const startDay = clamp(dayOffset(firstDay, activeSelection.startDate), 0, days.length - 1);
    const endDay = clamp(dayOffset(firstDay, activeSelection.endDate), 0, days.length - 1);

    return {
      startRow: Math.min(...selectedRowIndexes),
      endRow: Math.max(...selectedRowIndexes),
      startDay: Math.min(startDay, endDay),
      endDay: Math.max(startDay, endDay)
    };
  }, [activeSelection, days.length, firstDay, selectionDraft, visibleItems]);
  const copyPlacementPreview = useMemo(() => {
    if (!copyPreview || !copyHoverTarget || visibleItems.length === 0 || days.length === 0) {
      return null;
    }

    const startRow = clamp(copyHoverTarget.rowIndex, 0, Math.max(visibleItems.length - 1, 0));
    const endRow = clamp(startRow + Math.max(copyPreview.rowSpan, 1) - 1, startRow, Math.max(visibleItems.length - 1, startRow));
    const startDay = clamp(copyHoverTarget.dayIndex, 0, Math.max(days.length - 1, 0));
    const endDay = clamp(startDay + Math.max(copyPreview.daySpan, 1) - 1, startDay, Math.max(days.length - 1, startDay));

    return {
      startRow,
      endRow,
      startDay,
      endDay,
      customerName: copyPreview.customerName
    };
  }, [copyHoverTarget, copyPreview, days.length, visibleItems.length]);
  const mobileMovePlacementPreview = useMemo(() => {
    if (!mobileMoveDraft || visibleItems.length === 0 || days.length === 0) {
      return null;
    }

    const startRow = clamp(mobileMoveDraft.targetRow, 0, Math.max(visibleItems.length - 1, 0));
    const endRow = clamp(startRow + Math.max(mobileMoveDraft.rowSpan, 1) - 1, startRow, Math.max(visibleItems.length - 1, startRow));
    const startDay = clamp(mobileMoveDraft.targetDay, 0, Math.max(days.length - 1, 0));
    const endDay = clamp(startDay + Math.max(mobileMoveDraft.daySpan, 1) - 1, startDay, Math.max(days.length - 1, startDay));

    return {
      startRow,
      endRow,
      startDay,
      endDay,
      customerName: mobileMoveDraft.booking.customerName
    };
  }, [days.length, mobileMoveDraft, visibleItems.length]);
  const monthSegments = useMemo(() => buildMonthSegments(days), [days]);
  const scalingHighlightRange =
    bookingInteraction?.kind === "resize-vertical" ||
    bookingInteraction?.kind === "resize-start-corner" ||
    bookingInteraction?.kind === "resize-end-corner"
      ? {
          start: Math.min(bookingInteraction.startRow, bookingInteraction.endRow),
          end: Math.max(bookingInteraction.startRow, bookingInteraction.endRow)
        }
      : null;
  const activeInteractionBookingIdsForLayout =
    bookingInteraction && "bookingIds" in bookingInteraction
      ? new Set(bookingInteraction.bookingIds)
      : bookingInteraction
        ? new Set([bookingInteraction.booking.id])
        : new Set<string>();
  const hideInteractionBookingsInLayout =
    bookingInteraction?.kind === "move-project" ||
    bookingInteraction?.kind === "resize-vertical" ||
    bookingInteraction?.kind === "resize-start-corner" ||
    bookingInteraction?.kind === "resize-end-corner";

  const rowStates: RowRenderState[] = visibleItems.map((item, rowIndex) => {
    const verticalResizeRange =
      bookingInteraction?.kind === "resize-vertical" ||
      bookingInteraction?.kind === "resize-start-corner" ||
      bookingInteraction?.kind === "resize-end-corner" ||
      bookingInteraction?.kind === "move-project"
        ? {
            start: Math.min(bookingInteraction.startRow, bookingInteraction.endRow),
            end: Math.max(bookingInteraction.startRow, bookingInteraction.endRow)
          }
        : null;
    const previewOnRow = bookingInteraction?.kind === "move" && bookingInteraction.equipmentItemId === item.id;
    const previewFromOtherRow =
      bookingInteraction?.kind === "move" &&
      bookingInteraction.booking.equipmentItemId !== item.id &&
      bookingInteraction.equipmentItemId === item.id
        ? bookingInteraction.booking
        : null;
    const rowBookings: BookingWithContext[] = (previewFromOtherRow ? [...item.bookings, previewFromOtherRow] : item.bookings).map(
      (booking) => ({
        ...booking,
        itemName: item.name,
        categoryName: item.categoryName
      })
    );
    const renderedBookings = rowBookings
      .map((booking) => {
        const bookingPreview = getBookingPreviewDraft(booking, bookingInteraction);

        return bookingPreview
          ? {
              ...booking,
              equipmentItemId: bookingPreview.equipmentItemId,
              startDate: bookingPreview.startDate,
              endDate: bookingPreview.endDate
            }
          : booking;
      })
      .filter(
        (booking) =>
          booking.equipmentItemId === item.id &&
          (!hideInteractionBookingsInLayout || !activeInteractionBookingIdsForLayout.has(booking.id))
      );
    const rowLayout = buildRowBookingLayout(renderedBookings);
    const hasStackedLanes = rowLayout.maxLane > 0;
    const bookingBarHeightForRow = uniformBookingBarHeight;
    const bookingTopOffsetForRow = uniformBookingTopOffset;
    const laneStep = hasStackedLanes ? bookingBarHeightForRow + stackedLaneGap : 0;
    const rowMinHeight = Math.max(
      effectiveRowHeight,
      bookingBarHeightForRow + rowLayout.maxLane * laneStep + bookingTopOffsetForRow + Math.max(bookingTopOffsetForRow, 1)
    );

    return {
      item,
      rowIndex,
      previewOnRow: previewOnRow || Boolean(verticalResizeRange && rowIndex >= verticalResizeRange.start && rowIndex <= verticalResizeRange.end),
      renderedBookings,
      rowLayout,
      hasStackedLanes,
      bookingBarHeight: bookingBarHeightForRow,
      bookingTopOffset: bookingTopOffsetForRow,
      laneStep,
      rowMinHeight
    };
  });

  const rowStateByItemId = new Map(rowStates.map((rowState) => [rowState.item.id, rowState]));
  const { mergedBlockByBookingId, mergedBlocksByBottomRowIndex, mergedBlocksByTopRowIndex } = buildMergedBookingBlocks({
    dayCount: days.length,
    effectiveDayWidth,
    firstDay,
    labelWidth: effectiveLabelWidth,
    rowStates
  });
  const verticalResizePreview = useMemo<VerticalResizePreviewBlock | null>(() => {
    if (
      bookingInteraction?.kind !== "resize-vertical" &&
      bookingInteraction?.kind !== "resize-start-corner" &&
      bookingInteraction?.kind !== "resize-end-corner" &&
      bookingInteraction?.kind !== "move-project"
    ) {
      return null;
    }

    const previewStartRow = Math.min(bookingInteraction.startRow, bookingInteraction.endRow);
    const previewEndRow = Math.max(bookingInteraction.startRow, bookingInteraction.endRow);
    const previewRows = rowStates.slice(previewStartRow, previewEndRow + 1);
    const topOffset = previewRows[0]?.bookingTopOffset ?? 0;
    const totalHeight = previewRows.reduce((height, rowState) => height + rowState.rowMinHeight, 0);
    const previewStartDate = "startDate" in bookingInteraction ? bookingInteraction.startDate : bookingInteraction.booking.startDate;
    const previewEndDate = "endDate" in bookingInteraction ? bookingInteraction.endDate : bookingInteraction.booking.endDate;
    const startIndex = Math.max(0, dayOffset(firstDay, previewStartDate));
    const endIndex = Math.min(days.length - 1, dayOffset(firstDay, previewEndDate));
    const sourceMergedBlock = mergedBlockByBookingId.get(bookingInteraction.booking.id);
    const interactionBookingIds =
      "bookingIds" in bookingInteraction ? bookingInteraction.bookingIds : sourceMergedBlock?.bookingIds ?? [bookingInteraction.booking.id];
    const previewNeedsMergedBlock =
      interactionBookingIds.length > 1 ||
      bookingInteraction.kind === "move-project" ||
      bookingInteraction.kind === "resize-vertical";

    if (
      previewRows.length === 0 ||
      (!previewNeedsMergedBlock && previewStartRow === previewEndRow) ||
      endIndex < 0 ||
      startIndex > days.length - 1
    ) {
      return null;
    }

    return {
      bookingId: bookingInteraction.booking.id,
      bookingIds: interactionBookingIds,
      topRowIndex: previewStartRow,
      bottomRowIndex: previewEndRow,
      left: effectiveLabelWidth + startIndex * effectiveDayWidth + 3,
      width: Math.max((endIndex - startIndex + 1) * effectiveDayWidth - 6, 18),
      top: topOffset,
      height: Math.max(totalHeight - 1, 12),
      customerName: bookingInteraction.booking.customerName
    };
  }, [bookingInteraction, days.length, effectiveDayWidth, effectiveLabelWidth, firstDay, mergedBlockByBookingId, rowStates]);
  const activeInteractionBookingIds = useMemo(() => {
    if (!bookingInteraction) {
      return new Set<string>();
    }

    if ("bookingIds" in bookingInteraction) {
      return new Set(bookingInteraction.bookingIds);
    }

    return new Set([bookingInteraction.booking.id]);
  }, [bookingInteraction]);

  return (
    <div className={cn("overflow-hidden border border-line bg-white", mobileMode ? "rounded-[30px]" : "rounded-b-[14px]", mobileMode && selectionEnabled && "select-none")}>
      <div
        ref={scrollerRef}
        className={cn("overflow-auto overscroll-contain", mobileMode && selectionEnabled && "select-none")}
        onScroll={(event) => {
          const nextLeft = event.currentTarget.scrollLeft;
          const nextTop = event.currentTarget.scrollTop;
          const previousLeft = previousScrollPositionRef.current.left;

          scrollPositionRef.current = {
            left: nextLeft,
            top: nextTop
          };
          previousScrollPositionRef.current = {
            left: nextLeft,
            top: nextTop
          };

          maybeRequestFutureRange(nextLeft - previousLeft);
        }}
        onPointerMove={(event) => {
          if (!mobileMoveDraftRef.current || event.pointerType !== "touch") {
            return;
          }

          const target = resolveGridTarget(event.clientX, event.clientY);

          if (target) {
            setMobileMoveTarget(target);
          }
        }}
        onWheel={(event) => {
          if (mobileMode || interactionsLocked) {
            return;
          }

          const horizontalDelta =
            Math.abs(event.deltaX) > Math.abs(event.deltaY)
              ? event.deltaX
              : event.shiftKey
                ? event.deltaY
                : 0;

          if (horizontalDelta === 0) {
            return;
          }

          event.preventDefault();
          event.currentTarget.scrollLeft += horizontalDelta;
          maybeRequestFutureRange(horizontalDelta);
        }}
        style={{
          maxHeight: scrollerMaxHeight,
          touchAction: mobileMode && selectionEnabled ? "none" : "pan-x pan-y",
          userSelect: mobileMode && selectionEnabled ? "none" : "auto",
          WebkitTouchCallout: mobileMode && selectionEnabled ? "none" : "default",
          WebkitUserSelect: mobileMode && selectionEnabled ? "none" : "auto"
        }}
      >
        <div className="min-w-max" style={{ minWidth: "100%", width: effectiveLabelWidth + days.length * effectiveDayWidth }}>
          <div className="sticky top-0 z-30 border-b border-line bg-[#f9f4eb]/95 backdrop-blur">
            <div className="grid border-b border-line/70" style={{ gridTemplateColumns }}>
              <div
                className={cn(
                  "sticky left-0 z-30 row-span-2 border-r border-line bg-[#f9f4eb]/95",
                  mobileMode ? "px-4 py-3" : "px-2 py-1.5"
                )}
                style={{ gridRow: "1 / span 2" }}
              >
                <p className={cn("uppercase tracking-[0.22em] text-muted", mobileMode ? "text-xs" : "text-[10px]")}>Urządzenia</p>
                {!mobileMode ? (
                  <button
                    aria-label="Zmień szerokość kolumny urządzeń"
                    className="absolute inset-y-0 right-[-7px] z-40 flex w-4 cursor-col-resize touch-none items-center justify-center"
                    type="button"
                    onPointerDown={(event) => {
                      event.preventDefault();
                      event.stopPropagation();
                      labelResizeStateRef.current = {
                        startX: event.clientX,
                        startWidth: effectiveLabelWidth,
                        currentWidth: effectiveLabelWidth
                      };
                      setLabelWidthDraft(effectiveLabelWidth);
                      setLabelResizing(true);
                    }}
                  >
                    <span className="h-14 w-[3px] rounded-full bg-[#22342d]/35 transition hover:bg-[#22342d]/65" />
                  </button>
                ) : null}
              </div>
              {monthSegments.map((segment) => (
                <div
                  key={`${segment.label}-${segment.startIndex}`}
                  className={cn(
                    "border-r border-line text-center font-semibold text-ink",
                    mobileMode ? "px-2 py-2 text-xs" : "px-1 py-1 text-[11px]"
                  )}
                  style={{ gridColumn: `${segment.startIndex + 2} / span ${segment.length}` }}
                >
                  {segment.label}
                </div>
              ))}
            </div>

            <div className="grid" style={{ gridTemplateColumns }}>
              <div className="sticky left-0 z-30 border-r border-line bg-[#f9f4eb]/95" />
              {days.map((day) => {
                const date = new Date(`${day}T12:00:00.000Z`);

                return (
                  <div
                    key={day}
                    className={cn(
                      "border-r border-line text-center",
                      mobileMode ? "px-2 py-2.5" : "px-1 py-1.5",
                      day === today && "bg-today"
                    )}
                  >
                    <p className={cn("font-semibold text-ink", mobileMode ? "text-sm" : "text-[11px]")}>{date.getUTCDate()}</p>
                  </div>
                );
              })}
            </div>
          </div>

          {groups.map((group, groupIndex) => {
            const isCollapsed = collapsedGroups.includes(group.categoryId);

            return (
              <div key={group.categoryId}>
                <div className="grid border-b border-line/70 bg-[#f2ece1]" style={{ gridTemplateColumns }}>
                  <button
                    className={cn(
                      "sticky left-0 z-20 flex border-r border-line bg-[#f2ece1] text-left",
                      mobileMode ? "items-center gap-3 px-4 py-3" : "items-center gap-2 px-2 py-1.5"
                    )}
                    onClick={() => onToggleGroup(group.categoryId)}
                  >
                    {isCollapsed ? <ChevronRight className="h-4 w-4 text-muted" /> : <ChevronDown className="h-4 w-4 text-muted" />}
                    <div className="min-w-0">
                      <p className={cn("font-semibold text-ink", mobileMode ? "text-sm" : "text-xs leading-none")}>{group.categoryName}</p>
                    </div>
                    {onMoveGroup ? (
                      <div className="ml-auto flex items-center gap-1">
                        <button
                          className="flex h-6 w-6 items-center justify-center rounded-md text-muted transition hover:bg-white/70 hover:text-ink disabled:cursor-default disabled:opacity-35"
                          disabled={groupIndex <= 0}
                          type="button"
                          onClick={(event) => {
                            event.preventDefault();
                            event.stopPropagation();
                            void onMoveGroup(group.categoryId, -1);
                          }}
                        >
                          <ArrowUp className="h-3.5 w-3.5" />
                        </button>
                        <button
                          className="flex h-6 w-6 items-center justify-center rounded-md text-muted transition hover:bg-white/70 hover:text-ink disabled:cursor-default disabled:opacity-35"
                          disabled={groupIndex >= groups.length - 1}
                          type="button"
                          onClick={(event) => {
                            event.preventDefault();
                            event.stopPropagation();
                            void onMoveGroup(group.categoryId, 1);
                          }}
                        >
                          <ArrowDown className="h-3.5 w-3.5" />
                        </button>
                      </div>
                    ) : null}
                  </button>
                  <div
                    className={cn("flex items-center gap-2", mobileMode ? "px-4 py-3" : "px-2 py-1.5")}
                    style={{ gridColumn: `2 / span ${days.length}` }}
                  >
                    <Badge tone="neutral">{group.totalItems} w grupie</Badge>
                    {isCollapsed ? <Badge tone="accent">Zwinięte</Badge> : null}
                  </div>
                </div>

                {!isCollapsed
                  ? group.items.map((item) => {
                      const rowState = rowStateByItemId.get(item.id);

                      if (!rowState) {
                        return null;
                      }

                      const rowIndex = rowState.rowIndex;
                      const itemLabel =
                        item.useShortNameOnTimeline && item.shortName?.trim()
                          ? `${item.shortName.trim()} #${group.items.findIndex((groupItem) => groupItem.id === item.id) + 1}`
                          : item.name;
                      const topMergedBlocks = mergedBlocksByTopRowIndex.get(rowIndex) ?? [];
                      const bottomMergedBlocks = mergedBlocksByBottomRowIndex.get(rowIndex) ?? [];
                      const previewStartsOnRow = verticalResizePreview?.topRowIndex === rowIndex;
                      const highlightLabelColumn =
                        rowState.previewOnRow ||
                        Boolean(
                          selectionPreview &&
                            rowIndex >= selectionPreview.startRow &&
                            rowIndex <= selectionPreview.endRow
                        ) ||
                        Boolean(
                          scalingHighlightRange &&
                            rowIndex >= scalingHighlightRange.start &&
                            rowIndex <= scalingHighlightRange.end
                        ) ||
                        Boolean(
                          mobileMovePlacementPreview &&
                            rowIndex >= mobileMovePlacementPreview.startRow &&
                            rowIndex <= mobileMovePlacementPreview.endRow
                        );

                      return (
                        <div
                          key={item.id}
                          ref={(element) => setRowElement(item.id, element)}
                          className={cn(
                            "relative grid border-b border-line/60",
                            rowState.previewOnRow && "bg-accent/5",
                            selectionPreview &&
                              rowIndex >= selectionPreview.startRow &&
                              rowIndex < selectionPreview.endRow &&
                              "border-b-transparent"
                          )}
                          style={{ gridTemplateColumns, minHeight: rowState.rowMinHeight }}
                        >
                          <div
                            className={cn(
                              "sticky left-0 z-20 border-r border-line",
                              highlightLabelColumn ? "bg-[#e8e6df]" : "bg-white",
                              mobileMode ? "flex items-center gap-2 px-2 py-1" : "px-2 py-1"
                            )}
                            title={`${item.name} • ${item.serialNumber || "Brak S/N"}${item.assetTag ? ` • ${item.assetTag}` : ""}`}
                          >
                            {mobileMode ? (
                              <div className="rounded-xl bg-[#eff4ef] p-1 text-accent">
                                <LaptopMinimalCheck className="h-3.5 w-3.5" />
                              </div>
                            ) : null}
                            <div className="min-w-0">
                              <p className={cn("truncate font-semibold text-ink", mobileMode ? "text-sm leading-none" : "text-[14px] leading-none")}>
                                {itemLabel}
                              </p>
                            </div>
                          </div>

                          {selectionPreview &&
                          rowIndex >= selectionPreview.startRow &&
                          rowIndex <= selectionPreview.endRow ? (
                            <div
                              className={cn(
                                "pointer-events-none absolute z-[2] border-[#3bb856] bg-[rgba(151,245,118,0.52)]",
                                selectionPreview.startRow === selectionPreview.endRow && "rounded-lg border-2",
                                selectionPreview.startRow !== selectionPreview.endRow &&
                                  rowIndex === selectionPreview.startRow &&
                                  "rounded-t-lg border-l-2 border-r-2 border-t-2",
                                selectionPreview.startRow !== selectionPreview.endRow &&
                                  rowIndex === selectionPreview.endRow &&
                                  "rounded-b-lg border-b-2 border-l-2 border-r-2",
                                selectionPreview.startRow !== selectionPreview.endRow &&
                                  rowIndex > selectionPreview.startRow &&
                                  rowIndex < selectionPreview.endRow &&
                                  "border-l-2 border-r-2"
                              )}
                              style={{
                                left: effectiveLabelWidth + selectionPreview.startDay * effectiveDayWidth + 1,
                                width: Math.max((selectionPreview.endDay - selectionPreview.startDay + 1) * effectiveDayWidth - 2, 8),
                                top: selectionPreview.startRow === selectionPreview.endRow || rowIndex === selectionPreview.startRow ? 1 : -1,
                                bottom:
                                  selectionPreview.startRow === selectionPreview.endRow || rowIndex === selectionPreview.endRow ? 2 : -1
                              }}
                            />
                          ) : null}

                          {days.map((day, dayIndex) => {
                            const busy = rowState.renderedBookings.some((booking) => isDateInsideBooking(day, booking));
                            const conflictDay = !suppressConflictIndicators && rowState.rowLayout.conflictDays.has(day);

                            return (
                              <div
                                key={`${item.id}-${day}`}
                                className={cn(
                                  "border-r border-line/50 transition",
                                  conflictDay ? "bg-[#f5cfd0]" : busy ? "bg-busy/35" : "bg-free/65",
                                  day === today && !conflictDay && "bg-today",
                                  selectionEnabled && !interactionsLocked && "hover:bg-accent/10"
                                )}
                                onPointerDown={(event) => {
                                  if (startMobileDropLongPress(event, { rowIndex, dayIndex })) {
                                    return;
                                  }

                                  if (copyPreview && onCopyDrop && event.button === 0 && !interactionsLocked) {
                                    event.preventDefault();
                                    event.stopPropagation();
                                    onCopyDrop(resolveCopyDropTarget(rowIndex, dayIndex));
                                    return;
                                  }

                                  if (event.button !== 0 || !selectionEnabled || interactionsLocked) {
                                    return;
                                  }

                                  event.preventDefault();
                                  event.currentTarget.setPointerCapture?.(event.pointerId);
                                  interactionMovedRef.current = false;
                                  interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                  setBookingInteraction(null);
                                  setSelectionDraft({
                                    startRow: rowIndex,
                                    endRow: rowIndex,
                                    startDay: dayIndex,
                                    endDay: dayIndex
                                  });
                                }}
                                onPointerEnter={() => {
                                  if (mobileMoveDraftRef.current) {
                                    setMobileMoveTarget({ rowIndex, dayIndex });
                                  }

                                  if (copyPreview) {
                                    updateCopyHoverTarget({ rowIndex, dayIndex });
                                  }

                                  if (!selectionDraftRef.current || interactionsLocked) {
                                    return;
                                  }

                                  updateSelectionTarget({ rowIndex, dayIndex });
                                }}
                                onPointerMove={(event) => {
                                  updateMobileDropLongPress(event, { rowIndex, dayIndex });

                                  if (copyPreview) {
                                    updateCopyHoverTarget({ rowIndex, dayIndex });
                                  }

                                  if (!selectionDraftRef.current || interactionsLocked) {
                                    return;
                                  }

                                  event.preventDefault();
                                  updateSelectionTarget({ rowIndex, dayIndex });
                                }}
                                onPointerUp={() => {
                                  cancelMobileDropLongPress();
                                }}
                                onPointerCancel={() => {
                                  cancelMobileDropLongPress();
                                }}
                              />
                            );
                          })}

                          {copyPlacementPreview &&
                          rowIndex >= copyPlacementPreview.startRow &&
                          rowIndex <= copyPlacementPreview.endRow ? (
                            <div
                              className={cn(
                                "pointer-events-none absolute z-[12] flex items-center justify-center overflow-hidden rounded-[5px] border border-dashed border-[#2e8e44] bg-[rgba(121,217,139,0.38)] px-2 text-center font-semibold text-[#0f4320]",
                                mobileMode ? "text-sm" : "text-[11px] leading-none"
                              )}
                              style={{
                                left: effectiveLabelWidth + copyPlacementPreview.startDay * effectiveDayWidth + 3,
                                width: Math.max((copyPlacementPreview.endDay - copyPlacementPreview.startDay + 1) * effectiveDayWidth - 6, 18),
                                top: rowIndex === copyPlacementPreview.startRow ? 0 : -1,
                                bottom: rowIndex === copyPlacementPreview.endRow ? 1 : -1
                              }}
                            >
                              <span className="pointer-events-none relative -top-[1px] block max-w-full truncate px-2">
                                {copyPlacementPreview.customerName}
                              </span>
                            </div>
                          ) : null}

                          {mobileMovePlacementPreview &&
                          rowIndex >= mobileMovePlacementPreview.startRow &&
                          rowIndex <= mobileMovePlacementPreview.endRow ? (
                            <div
                              className={cn(
                                "pointer-events-none absolute z-[13] flex items-center justify-center overflow-hidden rounded-[5px] border border-[#1d8f47] bg-[rgba(121,217,139,0.58)] px-2 text-center font-semibold text-[#0f4320] ring-2 ring-[#1d8f47]/15",
                                mobileMode ? "text-sm" : "text-[11px] leading-none"
                              )}
                              style={{
                                left: effectiveLabelWidth + mobileMovePlacementPreview.startDay * effectiveDayWidth + 3,
                                width: Math.max((mobileMovePlacementPreview.endDay - mobileMovePlacementPreview.startDay + 1) * effectiveDayWidth - 6, 18),
                                top: rowIndex === mobileMovePlacementPreview.startRow ? 0 : -1,
                                bottom: rowIndex === mobileMovePlacementPreview.endRow ? 1 : -1
                              }}
                            >
                              <span className="pointer-events-none relative -top-[1px] block max-w-full truncate px-2">
                                {mobileMovePlacementPreview.customerName}
                              </span>
                            </div>
                          ) : null}

                          {topMergedBlocks.map((block) => (
                            <div
                              key={block.blockId}
                              className={cn(
                                "group absolute z-10 flex items-center justify-center overflow-visible rounded-[5px] bg-[#79d98b] font-semibold text-[#0f4320]",
                                block.bookingIds.some((bookingId) => activeInteractionBookingIds.has(bookingId)) && "opacity-0",
                                block.bookingIds.some((bookingId) => mobileMoveDraft?.bookingIds.includes(bookingId)) && "opacity-0",
                                mobileMode ? "px-3 text-sm" : "px-2 text-[11px] leading-none"
                              )}
                              role="button"
                              tabIndex={0}
                              style={{
                                height: block.height,
                                left: block.left,
                                top: block.top,
                                width: block.width,
                                touchAction: "none",
                                userSelect: "none",
                                WebkitTouchCallout: "none",
                                WebkitUserSelect: "none"
                              }}
                              onKeyDown={(event) => {
                                if (event.key === "Enter" || event.key === " ") {
                                  event.preventDefault();
                                  onBookingClick(block.representative, block.bookingIds);
                                }
                              }}
                              onContextMenu={(event) => {
                                if (mobileMode) {
                                  event.preventDefault();
                                  event.stopPropagation();
                                  cancelMobileBookingLongPress();
                                  return;
                                }

                                if (!onBookingCopy) {
                                  return;
                                }

                                event.preventDefault();
                                event.stopPropagation();
                                onBookingCopy(block.representative, block.bookingIds);
                              }}
                              onPointerDown={(event) => {
                                if (event.button !== 0) {
                                  return;
                                }

                                if (mobileMode && event.pointerType === "touch") {
                                  const target = resolveGridTarget(event.clientX, event.clientY) ?? {
                                    rowIndex: block.topRowIndex,
                                    dayIndex: Math.max(0, dayOffset(firstDay, block.representative.startDate))
                                  };

                                  if (mobileMoveDraftRef.current) {
                                    startMobileDropLongPress(event, target);
                                  } else {
                                    startMobileBookingLongPress(
                                      event,
                                      block.representative,
                                      block.bookingIds,
                                      block.topRowIndex,
                                      block.bottomRowIndex
                                    );
                                  }

                                  return;
                                }

                                if (copyPreview && onCopyDrop && event.button === 0 && !interactionsLocked) {
                                  const target = resolveGridTarget(event.clientX, event.clientY);

                                  event.preventDefault();
                                  event.stopPropagation();
                                  onCopyDrop(resolveCopyDropTarget(target?.rowIndex ?? block.topRowIndex, target?.dayIndex ?? 0));
                                  return;
                                }

                                if (interactionsLocked) {
                                  return;
                                }

                                const target = resolveGridTarget(event.clientX, event.clientY);

                                event.preventDefault();
                                event.stopPropagation();
                                setMobileActionMenu(null);
                                interactionMovedRef.current = false;
                                interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                setSelectionDraft(null);
                                setBookingInteraction({
                                  kind: "move-project",
                                  booking: block.representative,
                                  bookingIds: block.bookingIds,
                                  startDate: block.representative.startDate,
                                  endDate: block.representative.endDate,
                                  startRow: block.topRowIndex,
                                  endRow: block.bottomRowIndex,
                                  initialStartRow: block.topRowIndex,
                                  initialEndRow: block.bottomRowIndex,
                                  pointerStartDay: target?.dayIndex ?? Math.max(0, dayOffset(firstDay, block.representative.startDate)),
                                  rowPointerOffset: target ? target.rowIndex - block.topRowIndex : 0
                                });
                              }}
                              onPointerEnter={(event) => {
                                if (copyPreview) {
                                  const target = resolveGridTarget(event.clientX, event.clientY);

                                  if (target) {
                                    updateCopyHoverTarget(target);
                                  }

                                  return;
                                }

                                setHoveredMergedBlockId(block.blockId);
                              }}
                              onPointerLeave={() => {
                                if (copyPreview) {
                                  return;
                                }

                                setHoveredMergedBlockId((current) => (current === block.blockId ? null : current));
                              }}
                              onPointerMove={(event) => {
                                if (mobileMode && event.pointerType === "touch" && mobileMoveDraftRef.current) {
                                  const target = resolveGridTarget(event.clientX, event.clientY);
                                  updateMobileDropLongPress(event, target ?? undefined);
                                  return;
                                }

                                updateMobileBookingLongPress(event);

                                if (!copyPreview) {
                                  return;
                                }

                                const target = resolveGridTarget(event.clientX, event.clientY);

                                if (target) {
                                  updateCopyHoverTarget(target);
                                }
                              }}
                              onPointerUp={(event) => {
                                finishMobileBookingTouch(event, block.representative, block.bookingIds);
                              }}
                              onPointerCancel={(event) => {
                                if (mobileMode && event.pointerType === "touch") {
                                  cancelMobileBookingLongPress();
                                  unlockMobileNativeSelection();
                                }
                              }}
                              onTouchStart={suppressMobileNativeTouch}
                              onTouchMove={suppressMobileNativeTouch}
                            >
                              <span
                                className={cn(
                                  "pointer-events-none relative block max-w-full px-2 text-center select-none",
                                  block.width < 180
                                    ? "-top-[1px] whitespace-normal break-words leading-[1.15]"
                                    : "-top-[2px] truncate"
                                )}
                              >
                                {block.representative.customerName}
                              </span>
                              <span
                                aria-hidden="true"
                                className={cn(
                                  bookingHandleClassName,
                                  !mobileMode &&
                                    hoveredMergedBlockId !== block.blockId &&
                                    !block.bookingIds.includes(activeBookingId ?? "") &&
                                    "opacity-0"
                                )}
                                style={{
                                  height: bookingCornerHandleSize,
                                  left: 0,
                                  top: 0,
                                  transform: `translate(-${bookingCornerHandleTranslate}%, -${bookingCornerHandleTranslate}%)`,
                                  width: bookingCornerHandleSize
                                }}
                                onPointerDown={(event) => {
                                  if (event.button !== 0) {
                                    return;
                                  }

                                  if (copyPreview && onCopyDrop && event.button === 0 && !interactionsLocked) {
                                    const target = resolveGridTarget(event.clientX, event.clientY);

                                    event.preventDefault();
                                    event.stopPropagation();
                                    onCopyDrop(
                                      resolveCopyDropTarget(
                                        target?.rowIndex ?? rowIndex,
                                        target?.dayIndex ?? Math.max(0, dayOffset(firstDay, block.representative.startDate))
                                      )
                                    );
                                    return;
                                  }

                                  if (interactionsLocked) {
                                    return;
                                  }

                                  event.preventDefault();
                                  event.stopPropagation();
                                  interactionMovedRef.current = false;
                                  interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                  setSelectionDraft(null);
                                  setBookingInteraction({
                                    kind: "resize-start-corner",
                                    booking: block.representative,
                                    bookingIds: block.bookingIds,
                                    equipmentItemId: block.representative.equipmentItemId,
                                    startDate: block.representative.startDate,
                                    endDate: block.representative.endDate,
                                    startRow: block.topRowIndex,
                                    endRow: block.bottomRowIndex,
                                    initialStartRow: block.topRowIndex,
                                    initialEndRow: block.bottomRowIndex,
                                    pointerStartDay: Math.max(0, dayOffset(firstDay, block.representative.startDate)),
                                    allowHorizontalResize: true
                                  });
                                }}
                              >
                                <CornerResizeMarker corner="top-left" />
                              </span>
                              <span
                                aria-hidden="true"
                                className={cn(
                                  bookingHandleClassName,
                                  !mobileMode &&
                                    hoveredMergedBlockId !== block.blockId &&
                                    !block.bookingIds.includes(activeBookingId ?? "") &&
                                    "opacity-0"
                                )}
                                style={{
                                  height: bookingCornerHandleSize,
                                  right: 0,
                                  bottom: 0,
                                  transform: `translate(${bookingCornerHandleTranslate}%, ${bookingCornerHandleTranslate}%)`,
                                  width: bookingCornerHandleSize
                                }}
                                onPointerDown={(event) => {
                                  if (event.button !== 0) {
                                    return;
                                  }

                                  if (interactionsLocked) {
                                    return;
                                  }

                                  event.preventDefault();
                                  event.stopPropagation();
                                  interactionMovedRef.current = false;
                                  interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                  setSelectionDraft(null);
                                  setBookingInteraction({
                                    kind: "resize-end-corner",
                                    booking: block.representative,
                                    bookingIds: block.bookingIds,
                                    equipmentItemId: block.representative.equipmentItemId,
                                    startDate: block.representative.startDate,
                                    endDate: block.representative.endDate,
                                    startRow: block.topRowIndex,
                                    endRow: block.bottomRowIndex,
                                    initialStartRow: block.topRowIndex,
                                    initialEndRow: block.bottomRowIndex,
                                    pointerStartDay: Math.max(0, dayOffset(firstDay, block.representative.endDate)),
                                    allowHorizontalResize: true
                                  });
                                }}
                              >
                                <CornerResizeMarker corner="bottom-right" />
                              </span>
                            </div>
                          ))}

                          {previewStartsOnRow && verticalResizePreview ? (
                            <div
                              className={cn(
                                "pointer-events-none absolute z-[11] flex items-center justify-center overflow-visible rounded-[5px] bg-[#79d98b] font-semibold text-[#0f4320] ring-2 ring-[#1d8f47]/20",
                                mobileMode ? "px-3 text-sm" : "px-2 text-[11px] leading-none"
                              )}
                              style={{
                                height: verticalResizePreview.height,
                                left: verticalResizePreview.left,
                                top: verticalResizePreview.top,
                                width: verticalResizePreview.width
                              }}
                            >
                              <span
                                className={cn(
                                  "pointer-events-none relative block max-w-full px-2 text-center select-none",
                                  verticalResizePreview.width < 180
                                    ? "-top-[1px] whitespace-normal break-words leading-[1.15]"
                                    : "-top-[2px] truncate"
                                )}
                              >
                                {verticalResizePreview.customerName}
                              </span>
                              <span
                                aria-hidden="true"
                                className={cn(bookingHandleClassName, "pointer-events-none")}
                                style={{
                                  height: bookingCornerHandleSize,
                                  left: 0,
                                  top: 0,
                                  transform: `translate(-${bookingCornerHandleTranslate}%, -${bookingCornerHandleTranslate}%)`,
                                  width: bookingCornerHandleSize
                                }}
                              >
                                <CornerResizeMarker corner="top-left" />
                              </span>
                              <span
                                aria-hidden="true"
                                className={cn(bookingHandleClassName, "pointer-events-none")}
                                style={{
                                  bottom: 0,
                                  height: bookingCornerHandleSize,
                                  right: 0,
                                  transform: `translate(${bookingCornerHandleTranslate}%, ${bookingCornerHandleTranslate}%)`,
                                  width: bookingCornerHandleSize
                                }}
                              >
                                <CornerResizeMarker corner="bottom-right" />
                              </span>
                            </div>
                          ) : null}

                          {rowState.renderedBookings.map((booking) => {
                            const startIndex = Math.max(0, dayOffset(firstDay, booking.startDate));
                            const endIndex = Math.min(days.length - 1, dayOffset(firstDay, booking.endDate));

                            if (endIndex < 0 || startIndex > days.length - 1) {
                              return null;
                            }

                            const bookingPreview = bookingInteraction?.booking.id === booking.id ? bookingInteraction : null;
                            const laneIndex = rowState.rowLayout.laneByBookingId.get(booking.id) ?? 0;
                            const bookingHasConflict =
                              !suppressConflictIndicators && rowState.rowLayout.conflictBookingIds.has(booking.id);
                            const resizeHandleVisible = Boolean(lastDay && booking.endDate <= lastDay);
                            const mergedBlock = mergedBlockByBookingId.get(booking.id);
                            const hideUnderlyingBar = Boolean(mergedBlock);
                            const hideForVerticalPreview = Boolean(
                              verticalResizePreview &&
                                verticalResizePreview.bookingIds.includes(booking.id)
                            );
                            const hideForActiveInteractionPreview =
                              activeInteractionBookingIds.has(booking.id) &&
                              (bookingInteraction?.kind === "move-project" ||
                                bookingInteraction?.kind === "resize-vertical" ||
                                bookingInteraction?.kind === "resize-start-corner" ||
                                bookingInteraction?.kind === "resize-end-corner") &&
                              verticalResizePreview?.bookingIds.includes(booking.id);

                            return (
                              <div
                                key={`${booking.id}-${item.id}`}
                                aria-label={`${booking.customerName} • ${booking.startDate} - ${booking.endDate}`}
                                className={cn(
                                "group absolute flex items-center overflow-visible rounded-[5px] bg-[#79d98b] text-left font-semibold text-[#0f4320]",
                                  mobileMode ? "px-3 text-sm" : "px-2 text-[11px] leading-none",
                                  bookingHasConflict && "bg-[#efb7ab] text-[#6f251d] ring-1 ring-[#cf7d7d]/80",
                                  interactionsLocked ? "cursor-default" : "cursor-grab active:cursor-grabbing",
                                  bookingPreview && "z-10 ring-2 ring-[#1d8f47]/25",
                                  mobileMoveDraft?.bookingIds.includes(booking.id) && "opacity-0",
                                  (hideUnderlyingBar || hideForVerticalPreview || hideForActiveInteractionPreview) && "opacity-0"
                                )}
                                role="button"
                                style={{
                                  height: rowState.bookingBarHeight,
                                  left: effectiveLabelWidth + startIndex * effectiveDayWidth + 3,
                                  top: rowState.bookingTopOffset + laneIndex * rowState.laneStep,
                                  width: Math.max((endIndex - startIndex + 1) * effectiveDayWidth - 6, 18),
                                  touchAction: "none",
                                  userSelect: "none",
                                  WebkitTouchCallout: "none",
                                  WebkitUserSelect: "none"
                                }}
                                tabIndex={0}
                                onKeyDown={(event) => {
                                  if (event.key === "Enter" || event.key === " ") {
                                    event.preventDefault();
                                    onBookingClick(booking, [booking.id]);
                                  }
                                }}
                                onPointerDown={(event) => {
                                  if (event.button !== 0) {
                                    return;
                                  }

                                  if (mobileMode && event.pointerType === "touch") {
                                    const target = resolveGridTarget(event.clientX, event.clientY) ?? { rowIndex, dayIndex: startIndex };

                                    if (mobileMoveDraftRef.current) {
                                      startMobileDropLongPress(event, target);
                                    } else {
                                      startMobileBookingLongPress(event, booking, [booking.id], rowIndex, rowIndex);
                                    }

                                    return;
                                  }

                                  if (copyPreview && onCopyDrop && !interactionsLocked) {
                                    const target = resolveGridTarget(event.clientX, event.clientY);

                                    event.preventDefault();
                                    event.stopPropagation();
                                    onCopyDrop(resolveCopyDropTarget(target?.rowIndex ?? rowIndex, target?.dayIndex ?? startIndex));
                                    return;
                                  }

                                  if (interactionsLocked) {
                                    return;
                                  }
                                  const target = resolveGridTarget(event.clientX, event.clientY);

                                  event.preventDefault();
                                  event.stopPropagation();
                                  setMobileActionMenu(null);
                                  event.currentTarget.setPointerCapture?.(event.pointerId);
                                  interactionMovedRef.current = false;
                                  interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                  setSelectionDraft(null);

                                  setBookingInteraction({
                                    kind: "move",
                                    booking,
                                    equipmentItemId: booking.equipmentItemId,
                                    startDate: booking.startDate,
                                    endDate: booking.endDate,
                                    pointerStartDay: target?.dayIndex ?? startIndex
                                  });
                                }}
                                onPointerEnter={(event) => {
                                  if (copyPreview) {
                                    const target = resolveGridTarget(event.clientX, event.clientY);

                                    if (target) {
                                      updateCopyHoverTarget(target);
                                    }

                                    return;
                                  }

                                  setHoveredBookingId(booking.id);
                                }}
                                onPointerLeave={() => {
                                  if (copyPreview) {
                                    return;
                                  }

                                  setHoveredBookingId((current) => (current === booking.id ? null : current));
                                }}
                                onPointerMove={(event) => {
                                  if (mobileMode && event.pointerType === "touch" && mobileMoveDraftRef.current) {
                                    const target = resolveGridTarget(event.clientX, event.clientY);
                                    updateMobileDropLongPress(event, target ?? undefined);
                                    return;
                                  }

                                  updateMobileBookingLongPress(event);

                                  if (!copyPreview) {
                                    return;
                                  }

                                  const target = resolveGridTarget(event.clientX, event.clientY);

                                  if (target) {
                                    updateCopyHoverTarget(target);
                                  }
                                }}
                                onContextMenu={(event) => {
                                  if (mobileMode) {
                                    event.preventDefault();
                                    event.stopPropagation();
                                    cancelMobileBookingLongPress();
                                    return;
                                  }

                                  if (!onBookingCopy) {
                                    return;
                                  }

                                  event.preventDefault();
                                  event.stopPropagation();
                                  onBookingCopy(booking, [booking.id]);
                                }}
                                onPointerUp={(event) => {
                                  finishMobileBookingTouch(event, booking, [booking.id]);
                                }}
                                onPointerCancel={(event) => {
                                  if (mobileMode && event.pointerType === "touch") {
                                    cancelMobileBookingLongPress();
                                    unlockMobileNativeSelection();
                                  }
                                }}
                                onTouchStart={suppressMobileNativeTouch}
                                onTouchMove={suppressMobileNativeTouch}
                              >
                                <span className="pointer-events-none relative -top-[2px] truncate pr-3 select-none">{booking.customerName}</span>
                                {resizeHandleVisible ? (
                                  <>
                                    <span
                                      aria-hidden="true"
                                      className={cn(
                                        bookingHandleClassName,
                                        !mobileMode && hoveredBookingId !== booking.id && activeBookingId !== booking.id && "opacity-0"
                                      )}
                                      style={{
                                        height: bookingCornerHandleSize,
                                        left: 0,
                                        top: 0,
                                        transform: `translate(-${bookingCornerHandleTranslate}%, -${bookingCornerHandleTranslate}%)`,
                                        width: bookingCornerHandleSize
                                      }}
                                      onPointerDown={(event) => {
                                        if (event.button !== 0) {
                                          return;
                                        }

                                        if (interactionsLocked) {
                                          return;
                                        }

                                        event.preventDefault();
                                        event.stopPropagation();
                                        interactionMovedRef.current = false;
                                        interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                        setSelectionDraft(null);
                                        const target = resolveGridTarget(event.clientX, event.clientY);
                                        setBookingInteraction({
                                          kind: "resize-start-corner",
                                          booking,
                                          bookingIds: [booking.id],
                                          equipmentItemId: booking.equipmentItemId,
                                          startDate: booking.startDate,
                                          endDate: booking.endDate,
                                          startRow: rowIndex,
                                          endRow: rowIndex,
                                          initialStartRow: rowIndex,
                                          initialEndRow: rowIndex,
                                          pointerStartDay: target?.dayIndex ?? startIndex,
                                          allowHorizontalResize: true
                                        });
                                      }}
                                    >
                                      <CornerResizeMarker corner="top-left" />
                                    </span>
                                    <span
                                      aria-hidden="true"
                                      className={cn(
                                        bookingHandleClassName,
                                        !mobileMode && hoveredBookingId !== booking.id && activeBookingId !== booking.id && "opacity-0"
                                      )}
                                      style={{
                                        bottom: 0,
                                        height: bookingCornerHandleSize,
                                        right: 0,
                                        transform: `translate(${bookingCornerHandleTranslate}%, ${bookingCornerHandleTranslate}%)`,
                                        width: bookingCornerHandleSize
                                      }}
                                      onPointerDown={(event) => {
                                        if (event.button !== 0) {
                                          return;
                                        }

                                        if (interactionsLocked) {
                                          return;
                                        }

                                        event.preventDefault();
                                        event.stopPropagation();
                                        interactionMovedRef.current = false;
                                        interactionStartPointRef.current = { x: event.clientX, y: event.clientY };
                                        setSelectionDraft(null);
                                        const target = resolveGridTarget(event.clientX, event.clientY);
                                        setBookingInteraction({
                                          kind: "resize-end-corner",
                                          booking,
                                          bookingIds: [booking.id],
                                          equipmentItemId: booking.equipmentItemId,
                                          startDate: booking.startDate,
                                          endDate: booking.endDate,
                                          startRow: rowIndex,
                                          endRow: rowIndex,
                                          initialStartRow: rowIndex,
                                          initialEndRow: rowIndex,
                                          pointerStartDay: target?.dayIndex ?? endIndex,
                                          allowHorizontalResize: true
                                        });
                                      }}
                                    >
                                      <CornerResizeMarker corner="bottom-right" />
                                    </span>
                                  </>
                                ) : null}
                              </div>
                            );
                          })}
                        </div>
                      );
                    })
                  : null}
              </div>
            );
          })}
        </div>
      </div>
      {mobileActionMenu ? (
        <>
          <button
            aria-label="Zamknij menu rezerwacji"
            className="fixed inset-0 z-[70] cursor-default bg-transparent"
            type="button"
            onClick={() => setMobileActionMenu(null)}
          />
          <div
            className="fixed z-[80] w-[178px] overflow-hidden rounded-[8px] border border-line bg-white text-sm font-semibold text-ink shadow-[0_16px_34px_rgba(16,24,20,0.16)]"
            style={{
              left: mobileActionMenu.x,
              top: mobileActionMenu.y,
              touchAction: "none",
              userSelect: "none",
              WebkitTouchCallout: "none",
              WebkitUserSelect: "none"
            }}
            onContextMenu={(event) => event.preventDefault()}
          >
            {onBookingCopy ? (
              <button
                className="block w-full px-4 py-3 text-left hover:bg-[#fff2e8]"
                type="button"
                onClick={() => {
                  onBookingCopy(mobileActionMenu.booking, mobileActionMenu.bookingIds);
                  setMobileActionMenu(null);
                }}
              >
                Kopiuj
              </button>
            ) : null}
            <button
              className="block w-full border-t border-line px-4 py-3 text-left hover:bg-[#fff2e8]"
              type="button"
              onClick={() => {
                onBookingClick(mobileActionMenu.booking, mobileActionMenu.bookingIds);
                setMobileActionMenu(null);
              }}
            >
              Edytuj
            </button>
          </div>
        </>
      ) : null}
    </div>
  );
};
