function WorkItems({ snapshot }) {
  const isPhone = useIsPhone();
  const [filters, setFilters] = React.useState({ search: "", status: "all", type: "all", block: "all" });
  const [selectedId, setSelectedId] = React.useState("");
  const [taskEditor, setTaskEditor] = React.useState(null);
  const [detailOpen, setDetailOpen] = React.useState(false);
  const [typeFilter, setTypeFilter] = React.useState("all");
  const [collapsedIds, setCollapsedIds] = React.useState(() => new Set());
  const [detailIntent, setDetailIntent] = React.useState(null);

  const flatTree = flattenWorkTree(snapshot.projectTree || []);
  const itemById = React.useMemo(() => {
    const map = new Map();
    flatTree.forEach((item) => map.set(item.id, item));
    return map;
  }, [flatTree]);
  const childCountByParent = React.useMemo(() => buildDirectChildCountMap(flatTree), [flatTree]);
  const descendantCountByParent = React.useMemo(() => buildDescendantCountMap(flatTree), [flatTree]);
  const parentNodeIds = React.useMemo(() => Array.from(childCountByParent.keys()), [childCountByParent]);
  const projectBlocks = React.useMemo(() => getProjectBlocks(snapshot, flatTree), [snapshot.project?.blocks, flatTree]);
  const blockRootNames = React.useMemo(
    () => new Set(projectBlocks.map((block) => block.name)),
    [projectBlocks]
  );
  const blockSubtreeIds = React.useMemo(() => {
    if (filters.block === "all") return null;
    const ids = new Set();
    const root = flatTree.find((item) => item.type === "phase" && item.title === filters.block && blockRootNames.has(item.title));
    if (!root) return ids;
    const walk = (parentId) => {
      ids.add(parentId);
      flatTree.filter((item) => item.parentId === parentId).forEach((child) => walk(child.id));
    };
    walk(root.id);
    return ids;
  }, [filters.block, flatTree, blockRootNames]);
  const blockTaskCounts = React.useMemo(() => {
    const counts = new Map(projectBlocks.map((block) => [block.name, 0]));
    projectBlocks.forEach((block) => {
      const root = flatTree.find((item) => item.type === "phase" && item.title === block.name && blockRootNames.has(item.title));
      if (root) counts.set(block.name, descendantCountByParent.get(root.id) || 0);
    });
    return counts;
  }, [flatTree, projectBlocks, blockRootNames, descendantCountByParent]);
  const dependentsById = React.useMemo(() => buildDependentsIndex(flatTree), [flatTree]);
  const dependencyLinkCount = React.useMemo(() => {
    let count = 0;
    flatTree.forEach((item) => {
      if (!window.WorkPlanEditor.isLinkableDependencyType(item.type)) return;
      count += (item.dependencies || []).length;
    });
    return count;
  }, [flatTree]);
  const visibleItems = flatTree.filter((item) => {
    const matchesSearch = !filters.search || item.title.toLowerCase().includes(filters.search.toLowerCase());
    const matchesStatus = (() => {
      if (filters.status === "all") return true;
      if (filters.status === "schedule:delayed") {
        return item.rollup?.schedule?.status === "delayed";
      }
      if (filters.status === "schedule:at_risk") {
        return item.rollup?.schedule?.status === "at_risk";
      }
      return item.status === filters.status || item.rollup?.status === filters.status;
    })();
    const activeType = typeFilter !== "all" ? typeFilter : filters.type;
    const matchesType = activeType === "all" || item.type === activeType;
    const matchesBlock = filters.block === "all"
      || (blockSubtreeIds ? blockSubtreeIds.has(item.id) : false);
    if (!matchesSearch || !matchesStatus || !matchesType || !matchesBlock) return false;
    let parentId = item.parentId;
    while (parentId) {
      if (collapsedIds.has(parentId)) return false;
      parentId = itemById.get(parentId)?.parentId;
    }
    return true;
  });
  const selected = selectedId ? flatTree.find((item) => item.id === selectedId) : visibleItems.find((item) => item.type !== "phase");

  React.useEffect(() => {
    const focusId = sessionStorage.getItem("constructpro.focusWorkItemId");
    if (!focusId) return;
    sessionStorage.removeItem("constructpro.focusWorkItemId");
    const flat = flattenWorkTree(snapshot.projectTree || []);
    if (flat.some((item) => item.id === focusId)) {
      setSelectedId(focusId);
      setDetailOpen(true);
    }
  }, [snapshot.project.id, snapshot.projectTree]);

  const projectBlocksForDeps = React.useMemo(
    () => projectBlocks.map((block) => ({
      id: block.name,
      name: block.name,
      floor: block.floor,
      targetDays: block.targetDays,
      tasks: window.WorkPlanEditor.getBlockLinkableItemsFromTree(flatTree, block.name, blockRootNames)
    })),
    [flatTree, projectBlocks, blockRootNames]
  );

  const updateFilter = (key, value) => setFilters((current) => ({ ...current, [key]: value }));

  const closeTaskEditor = () => setTaskEditor(null);
  const closeDetail = () => {
    setDetailOpen(false);
    setDetailIntent(null);
  };

  const focusTask = (itemId, intent = null) => {
    setSelectedId(itemId);
    setDetailIntent(intent);
    setDetailOpen(true);
  };

  const handleSuggestionAction = (suggestion, item) => {
    if (!item) return;
    if (suggestion.action === "edit") {
      openEditEditor(item);
      return;
    }
    if (suggestion.action === "filter_delayed") {
      updateFilter("status", "schedule:delayed");
      return;
    }
    if (suggestion.action === "dpr") {
      focusTask(item.id, { tab: "dpr", openDpr: true });
      return;
    }
    focusTask(item.id, { tab: "general", focusStatus: true });
  };

  const taskSuggestions = React.useMemo(() => collectProjectTaskSuggestions(flatTree), [flatTree]);

  const blockRecordForName = (name) => {
    const fromProject = projectBlocks.find((block) => block.name === name);
    return {
      name: name || "Block A",
      floor: fromProject?.floor || "",
      targetDays: fromProject?.targetDays || 60
    };
  };

  const openTaskEditor = (preset = {}) => {
    const blockName = preset.blockName
      || (preset.parentItem ? resolveBlockName(preset.parentItem, itemById, blockRootNames) : "")
      || projectBlocks[0]?.name
      || "Block A";
    const block = blockRecordForName(blockName);
    const parentItem = preset.parentItem || (preset.parentId ? itemById.get(preset.parentId) : null);
    let parentId = preset.parentId || parentItem?.id || "";
    let draftType = preset.type || "task";
    let parentTaskId = null;
    if (parentItem?.type === "task") {
      parentTaskId = parentItem.id;
      draftType = preset.type || "subtask";
    } else if (parentItem?.type === "phase") {
      parentId = parentItem.id;
    }
    const phase = flatTree.find((item) => item.type === "phase" && item.title === block.name);
    const siblingTasks = window.WorkPlanEditor.getBlockTasksFromTree(flatTree, block.name, blockRootNames);
    const isQc = draftType === "qc";
    const draft = window.WorkPlanEditor.stripQcScheduling(window.WorkPlanEditor.createDraftTask({
      type: draftType,
      parentTaskId,
      ...(isQc ? {
        targetDays: 0,
        budgetPlanned: 0,
        startDate: "",
        dueDate: "",
        labor: window.WorkPlanEditor.emptyQcBreakdown().labor,
        materials: []
      } : {
        targetDays: block.targetDays || 30,
        ...window.WorkPlanEditor.defaultTaskDates({
          projectStart: snapshot.project.startDate || "",
          projectEnd: snapshot.project.endDate || "",
          parentTask: parentItem?.type === "task" ? parentItem : null,
          targetDays: block.targetDays || 30
        })
      })
    }));
    setTaskEditor({
      mode: "create",
      draft,
      block,
      parentId: parentId || phase?.id || "",
      assigneeRole: preset.assigneeRole || "Field Team Member",
      siblingTasks,
      projectBlocks: projectBlocksForDeps
    });
    if (parentItem?.id) setSelectedId(parentItem.id);
  };

  const openEditEditor = (item) => {
    if (item.type === "phase" && !item.parentId) return;
    setDetailOpen(false);
    const blockName = resolveBlockName(item, itemById, blockRootNames);
    const block = blockRecordForName(blockName);
    const siblingTasks = window.WorkPlanEditor.getBlockTasksFromTree(flatTree, block.name, blockRootNames);
    setTaskEditor({
      mode: "edit",
      itemId: item.id,
      draft: window.WorkPlanEditor.workItemToDraft(item, itemById),
      block,
      parentId: item.parentId || "",
      assigneeRole: item.assigneeRole || "Field Team Member",
      siblingTasks,
      projectBlocks: projectBlocksForDeps
    });
    setSelectedId(item.id);
  };

  const deleteWorkItem = (item, { skipConfirm = false } = {}) => {
    if (item.type === "phase") {
      window.ConstructProData.showToast("Block phases cannot be deleted here.");
      return false;
    }
    const childCount = descendantCountByParent.get(item.id) || 0;
    const childNote = childCount ? ` and ${childCount} nested item${childCount === 1 ? "" : "s"}` : "";
    if (!skipConfirm && !window.confirm(`Delete "${item.title}"${childNote}? This cannot be undone.`)) return false;
    window.ConstructProData.deleteWorkItem(item.id);
    if (selectedId === item.id) {
      setSelectedId("");
      setDetailOpen(false);
    }
    return true;
  };

  const saveTaskEditor = () => {
    if (!taskEditor?.draft?.title?.trim()) return;
    const { draft, block, mode, itemId, assigneeRole } = taskEditor;
    const normalizedDraft = window.WorkPlanEditor.isQcType(draft.type)
      ? window.WorkPlanEditor.stripQcScheduling(draft)
      : window.WorkPlanEditor.applySimpleCostSplit(draft, window.WorkPlanEditor.deriveSimpleCostSplit(draft));
    let parentId = taskEditor.parentId || "";
    if (normalizedDraft.parentTaskId) {
      parentId = normalizedDraft.parentTaskId;
    } else if (!parentId) {
      const phase = flatTree.find((item) => item.type === "phase" && item.title === block.name);
      parentId = phase?.id || "";
    }
    const isQc = window.WorkPlanEditor.isQcType(normalizedDraft.type);
    const payload = {
      projectId: snapshot.project.id,
      parentId,
      type: normalizedDraft.type,
      title: normalizedDraft.title.trim(),
      blockName: block.name,
      floor: block.floor || "",
      assigneeRole,
      startDate: isQc ? "" : (normalizedDraft.startDate || snapshot.project.startDate || ""),
      dueDate: isQc ? "" : (normalizedDraft.dueDate || snapshot.project.endDate || ""),
      budgetPlanned: isQc ? 0 : normalizedDraft.budgetPlanned,
      labor: isQc ? window.WorkPlanEditor.emptyQcBreakdown().labor : normalizedDraft.labor,
      materials: isQc ? [] : normalizedDraft.materials
    };
    let savedId = itemId;
    if (mode === "edit" && itemId) {
      window.ConstructProData.updateWorkItem(itemId, payload, { silent: true });
      setSelectedId(itemId);
    } else {
      const created = window.ConstructProData.createWorkItem({
        ...payload,
        checklist: [
          { id: `check_${Date.now()}_1`, label: "Checklist reviewed", done: false },
          { id: `check_${Date.now()}_2`, label: "Photo evidence required", done: false }
        ]
      }, { silent: true });
      if (created?.id) {
        savedId = created.id;
        setSelectedId(created.id);
        setDetailOpen(true);
      }
    }
    if (savedId && window.WorkPlanEditor.supportsDependencies(draft.type)) {
      const linkableItems = flatTree.filter((item) => window.WorkPlanEditor.isLinkableDependencyType(item.type));
      const patches = window.WorkPlanEditor.resolveDependencyPatches(draft, savedId, linkableItems);
      window.ConstructProData.applyDependencyPatches(patches);
    }
    window.ConstructProData.showToast(mode === "edit" ? "Work item updated" : "Work item created");
    setTaskEditor(null);
  };

  const addProjectBlock = (name, targetDays, floor) => {
    const created = window.ConstructProData.addProjectBlock({
      projectId: snapshot.project.id,
      name,
      targetDays,
      floor
    });
    if (created) updateFilter("block", created.name);
  };

  const updateProjectBlock = (blockName, name, targetDays, floor) => {
    const updated = window.ConstructProData.updateProjectBlock({
      projectId: snapshot.project.id,
      blockName,
      name,
      targetDays,
      floor
    });
    if (updated) {
      if (filters.block === blockName) updateFilter("block", updated.name);
    }
  };

  const selectWorkItem = (itemId) => {
    setSelectedId(itemId);
    const item = itemById.get(itemId);
    if (item && item.type !== "phase") setDetailOpen(true);
  };
  const toggleCollapse = (itemId) => {
    setCollapsedIds((current) => {
      const next = new Set(current);
      if (next.has(itemId)) next.delete(itemId);
      else next.add(itemId);
      return next;
    });
  };
  const collapseAll = () => {
    setCollapsedIds(new Set(parentNodeIds));
  };
  const expandAll = () => {
    setCollapsedIds(new Set());
  };
  const renderTaskEditor = () => {
    if (!taskEditor) return null;
    return (
      <WorkItemLiveForm
        draft={taskEditor.draft}
        block={taskEditor.block}
        siblingTasks={taskEditor.siblingTasks}
        projectBlocks={taskEditor.projectBlocks}
        projectStartDate={snapshot.project.startDate || ""}
        projectEndDate={snapshot.project.endDate || ""}
        assigneeRole={taskEditor.assigneeRole}
        onChange={(draft) => setTaskEditor((current) => ({ ...current, draft }))}
        onMetaChange={(meta) => setTaskEditor((current) => ({ ...current, ...meta }))}
        onSave={saveTaskEditor}
        onCancel={closeTaskEditor}
        saveLabel={taskEditor.mode === "edit" ? "Update task" : "Add task"}
      />
    );
  };

  const ff = window.ConstructProData.formatCurrency;
  const { rollups, project } = snapshot;
  const budgetPlanned = rollups.budgetPlanned || project.budgetTotal || 0;
  const budgetActual = rollups.budgetActual || project.budgetUsed || 0;
  const budgetUtilPct = budgetPlanned ? Math.round((budgetActual / budgetPlanned) * 100) : 0;
  const delayTrendParts = [];
  if (rollups.worstDaysLate) delayTrendParts.push(`${rollups.worstDaysLate}d worst overdue`);
  if (rollups.atRiskScheduleCount) delayTrendParts.push(`${rollups.atRiskScheduleCount} behind schedule`);
  if (!delayTrendParts.length) delayTrendParts.push("All tasks on track");
  const delayTrend = delayTrendParts.join(" · ");

  return (
    <div className={`work-items-page fade-in ${isPhone ? "pb-28" : ""}`}>
      <div className="mb-4 grid grid-cols-2 gap-3 md:mb-6 md:grid-cols-4 md:gap-4">
        <StatCard title="Work Items" value={rollups.total} trend={`${rollups.open} open`} icon={<Icons.schedule />} />
        <StatCard title="Planned Budget" value={ff(budgetPlanned)} trend={`${ff(budgetActual)} spent · ${budgetUtilPct}%`} icon={<Icons.finance />} tone="success" />
        <StatCard title="Delayed" value={rollups.delayedCount || 0} trend={delayTrend} icon={<Icons.alert />} tone={rollups.delayedCount ? "danger" : rollups.atRiskScheduleCount ? "warning" : "success"} />
        <StatCard title="Complete" value={rollups.completed} trend={`${rollups.progressPct}% rolled up`} icon={<Icons.check />} tone="success" />
      </div>

      {taskSuggestions.length ? (
        <TaskSuggestionsPanel
          suggestions={taskSuggestions}
          onSelect={(suggestion) => handleSuggestionAction(suggestion, itemById.get(suggestion.workItemId))}
        />
      ) : null}

      <div className="grid grid-cols-1 gap-6">
        <div className="space-y-4">
          <BlocksStructuresPanel
            blocks={projectBlocks}
            taskCounts={blockTaskCounts}
            selectedBlock={filters.block}
            onSelectBlock={(block) => updateFilter("block", block)}
            onAddBlock={addProjectBlock}
            onUpdateBlock={updateProjectBlock}
          />
          <Card>
            <div className="mb-4">
              <div className="work-filters">
                <label htmlFor="work-search" className="work-filters__search">
                  <span className="mb-1 block text-xs font-bold uppercase tracking-wider text-text-muted">Search</span>
                  <input id="work-search" value={filters.search} onChange={(event) => updateFilter("search", event.target.value)} placeholder="Search tasks, subtasks, QC..." className="w-full rounded-lg border border-border-light px-3 py-2 transition-colors focus:border-cta" />
                </label>
                <div className="work-filters__select">
                  <SelectField id="work-status-filter" label="Status" value={filters.status} onChange={(value) => updateFilter("status", value)}>
                    <option value="all">All statuses</option>
                    <option value="schedule:delayed">Delayed (overdue)</option>
                    <option value="schedule:at_risk">Behind schedule</option>
                    {window.ConstructProData.statuses.map((status) => <option key={status.id} value={status.id}>{status.label}</option>)}
                  </SelectField>
                </div>
              </div>
              <div className="mt-3 flex flex-wrap items-center justify-between gap-2">
                <WorkPlanFilterBar filter={typeFilter} onChange={setTypeFilter} />
              </div>
            </div>

            <div className="space-y-3">
              <div className="work-items-guide mb-1 md:hidden">
                {isPhone ? (
                  <>
                    <div className="work-items-guide__item">
                      <span className="work-items-guide__key">Tap</span>
                      <span>Tap a row to open details</span>
                    </div>
                    <div className="work-items-guide__item">
                      <span className="work-items-guide__key">+</span>
                      <span>Use Create to add task, subtask, or QC check</span>
                    </div>
                    <div className="work-items-guide__item">
                      <span className="work-items-guide__key">⋮</span>
                      <span>Edit or delete from menu</span>
                    </div>
                  </>
                ) : null}
              </div>
              {visibleItems.length === 0 && (
                <p className="rounded-xl border border-dashed border-border-light bg-surface-container-low p-8 text-center text-sm text-text-muted">No work items match your filters.</p>
              )}
              {visibleItems.length > 0 && (
                <div className="work-item-table work-item-table--modern mt-2">
                  <div className="work-item-table__toolbar">
                    <p className="work-item-table__count">
                      {visibleItems.length} item{visibleItems.length === 1 ? "" : "s"}
                      {filters.block !== "all" ? ` · ${filters.block}` : ""}
                      {dependencyLinkCount > 0 ? ` · ${dependencyLinkCount} sequence link${dependencyLinkCount === 1 ? "" : "s"}` : ""}
                    </p>
                    <div className="work-item-table__toolbar-actions">
                      <Button variant="secondary" onClick={() => openTaskEditor({ blockName: filters.block !== "all" ? filters.block : undefined })}>
                        <Icons.plus size={18} /> Create
                      </Button>
                      <button type="button" className="work-item-table__text-btn" onClick={expandAll}>Expand all</button>
                      <button type="button" className="work-item-table__text-btn" onClick={collapseAll}>Collapse all</button>
                    </div>
                  </div>
                  <div className="work-item-table__head hidden lg:grid">
                    <span>Work item</span>
                    <span>Budget</span>
                    <span>Status</span>
                    <span>Progress</span>
                    <span className="sr-only">Actions</span>
                  </div>
                  <div className="work-item-table__body">
                    {visibleItems.map((item) => (
                      <WorkItemRow
                        key={item.id}
                        item={item}
                        selected={selected?.id === item.id}
                        onSelect={() => selectWorkItem(item.id)}
                        onAddChild={(childType) => openTaskEditor({
                          parentItem: item,
                          parentId: item.id,
                          type: childType || (item.type === "phase" ? "task" : "subtask"),
                          blockName: resolveBlockName(item, itemById, blockRootNames)
                        })}
                        onEdit={() => openEditEditor(item)}
                        onDelete={() => deleteWorkItem(item)}
                        onToggleCollapse={() => toggleCollapse(item.id)}
                        isCollapsed={collapsedIds.has(item.id)}
                        childCount={descendantCountByParent.get(item.id) || 0}
                        blockName={resolveBlockName(item, itemById, blockRootNames)}
                        isMobile={isPhone}
                        onStatusChange={(nextStatus, note) => {
                          window.ConstructProData.updateWorkStatus({
                            workItemId: item.id,
                            status: nextStatus,
                            note,
                            role: "Admin"
                          });
                        }}
                        dependencies={getWorkItemDependencySummary(item, itemById, dependentsById, blockRootNames)}
                        onFocusDependency={focusTask}
                      />
                    ))}
                  </div>
                </div>
              )}
            </div>
          </Card>
        </div>
      </div>

      <TaskEditorModal
        open={Boolean(taskEditor)}
        title={taskEditor?.mode === "edit" ? "Edit work item" : "Create work item"}
        subtitle={taskEditor ? `${taskEditor.block.name}${taskEditor.block.floor ? ` · ${taskEditor.block.floor}` : ""} — estimates auto-calculate budget` : ""}
        onClose={closeTaskEditor}
      >
        {renderTaskEditor()}
      </TaskEditorModal>

      <TaskEditorModal
        open={detailOpen && Boolean(selected) && (selected.type !== "phase" || selected.parentId !== null)}
        wide
        title="Task preview"
        subtitle={selected ? `${selected.title} · ${selected.type}${selected.blockName || selected.location ? ` · ${selected.blockName || selected.location}` : ""}` : ""}
        onClose={closeDetail}
        headerAction={selected && (selected.type !== "phase" || selected.parentId !== null) ? (
          <Button
            variant="secondary"
            onClick={() => {
              closeDetail();
              openEditEditor(selected);
            }}
          >
            <Icons.settings size={18} /> Edit
          </Button>
        ) : null}
      >
        {selected && (selected.type !== "phase" || selected.parentId !== null) ? (
          <WorkItemDetail
            item={selected}
            embedded
            childCount={descendantCountByParent.get(selected.id) || 0}
            detailIntent={detailIntent}
            dependencies={getWorkItemDependencySummary(selected, itemById, dependentsById, blockRootNames)}
            onFocusTask={focusTask}
            onEdit={() => {
              closeDetail();
              openEditEditor(selected);
            }}
            onClose={() => {
              closeDetail();
              setSelectedId("");
            }}
            onDelete={(target) => {
              if (deleteWorkItem(target, { skipConfirm: true })) {
                closeDetail();
                setSelectedId("");
              }
            }}
          />
        ) : null}
      </TaskEditorModal>

      {isPhone && !taskEditor && !detailOpen && (
        <div className="m3-fab-stack">
          <button type="button" className="m3-fab m3-fab--extended" onClick={() => openTaskEditor({ blockName: filters.block !== "all" ? filters.block : undefined })} aria-label="Create work item">
            <Icons.plus size={24} />
            <span>Create</span>
          </button>
        </div>
      )}
    </div>
  );
}

function BlocksStructuresPanel({ blocks, taskCounts, selectedBlock, onSelectBlock, onAddBlock, onUpdateBlock }) {
  const [showAddForm, setShowAddForm] = React.useState(false);
  const [editingBlock, setEditingBlock] = React.useState(null);
  const [blockName, setBlockName] = React.useState("");
  const [blockFloor, setBlockFloor] = React.useState("");
  const [targetDays, setTargetDays] = React.useState(90);

  const resetForm = () => {
    setBlockName("");
    setBlockFloor("");
    setTargetDays(90);
  };

  const openAddForm = () => {
    setEditingBlock(null);
    resetForm();
    setShowAddForm(true);
  };

  const openEditForm = (block) => {
    setShowAddForm(false);
    setEditingBlock(block.name);
    setBlockName(block.name);
    setBlockFloor(block.floor || "");
    setTargetDays(Number(block.targetDays) || 90);
  };

  const closeForms = () => {
    setShowAddForm(false);
    setEditingBlock(null);
    resetForm();
  };

  const submitBlock = (event) => {
    event.preventDefault();
    if (!blockName.trim()) return;
    if (editingBlock) {
      onUpdateBlock?.(
        editingBlock,
        blockName.trim(),
        Number(targetDays) || 90,
        blockFloor.trim()
      );
    } else {
      onAddBlock(blockName.trim(), Number(targetDays) || 90, blockFloor.trim());
    }
    closeForms();
  };

  return (
    <Card>
      <SectionTitle
        title="Buildings / Blocks / Structures"
        subtitle="Filter tasks by block or structure."
      />
      <div className="work-blocks-scroll -mx-1 overflow-x-auto px-1 pb-1">
        <div className="flex min-w-max flex-wrap items-center gap-2 sm:min-w-0">
          <button
            type="button"
            onClick={() => onSelectBlock("all")}
            className={`rounded-full border px-3 py-1 text-xs font-bold transition-colors ${selectedBlock === "all" ? "border-cta bg-cta/10 text-cta" : "border-border-light text-text-muted hover:border-cta/40"}`}
          >
            All blocks
          </button>
          {blocks.map((block) => {
            const active = selectedBlock === block.name;
            const editing = editingBlock === block.name;
            const count = taskCounts.get(block.name) || 0;
            return (
              <div key={block.id || block.name} className="inline-flex items-center gap-1">
                <button
                  type="button"
                  onClick={() => onSelectBlock(active ? "all" : block.name)}
                  className={`rounded-full border px-3 py-1 text-xs font-bold transition-colors ${active || editing ? "border-cta bg-cta/10 text-cta" : "border-border-light text-text-muted hover:border-cta/40"}`}
                >
                  {block.name}
                  {block.floor ? <span className="ml-1 font-normal opacity-80">· {block.floor}</span> : null}
                  <span className="ml-1 opacity-70">({count})</span>
                </button>
                <button
                  type="button"
                  onClick={() => openEditForm(block)}
                  className="rounded-full border border-border-light px-2 py-1 text-[10px] font-bold uppercase tracking-wide text-text-muted transition-colors hover:border-cta/40 hover:text-cta"
                  aria-label={`Edit ${block.name}`}
                  title={`Edit ${block.name}`}
                >
                  Edit
                </button>
              </div>
            );
          })}
          <button
            type="button"
            onClick={() => (showAddForm ? closeForms() : openAddForm())}
            className="rounded-full border border-dashed border-cta px-3 py-1 text-xs font-bold text-cta transition-colors hover:bg-cta/10"
          >
            + Add block
          </button>
        </div>
      </div>
      {(showAddForm || editingBlock) && (
        <form onSubmit={submitBlock} className="mt-3 grid grid-cols-1 gap-3 rounded-xl border border-border-light bg-gray-50 p-3 sm:grid-cols-[1fr_1fr_100px_auto_auto] sm:items-end">
          <InputField id="block-name" label="Block / structure name" value={blockName} onChange={setBlockName} required placeholder="e.g. Block A, Tower 1" />
          <InputField id="block-floor" label="Floor" value={blockFloor} onChange={setBlockFloor} placeholder="e.g. Ground to G+4" />
          <InputField id="block-days" label="Target days" type="number" value={targetDays} onChange={setTargetDays} />
          <Button type="submit">{editingBlock ? "Save changes" : "Save block"}</Button>
          <Button type="button" variant="secondary" onClick={closeForms}>Cancel</Button>
        </form>
      )}
      {!blocks.length && (
        <p className="mt-3 text-sm text-text-muted">No blocks defined yet. Add a building, block, or structure to organize tasks.</p>
      )}
    </Card>
  );
}

function WorkItemRow({
  item,
  selected,
  onSelect,
  onAddChild,
  onEdit,
  onDelete,
  onToggleCollapse,
  isCollapsed,
  onStatusChange,
  childCount,
  blockName = "",
  isMobile = false,
  dependencies = null,
  onFocusDependency
}) {
  const ff = window.ConstructProData.formatCurrency;
  const typeMeta = window.WorkPlanEditor.getWorkItemTypeMeta(item);
  const status = item.rollup?.status || item.status;
  const statusLabel = window.WorkPlanEditor.formatWorkStatus(status);
  const progress = item.rollup?.progressPct ?? item.progressPct;
  const subtaskProgress = item.rollup?.subtaskProgress;
  const progressDisplay = subtaskProgress?.total
    ? `${subtaskProgress.done}/${subtaskProgress.total} · ${progress}%`
    : `${progress}%`;
  const budget = item.rollup?.budgetPlanned ?? item.budgetPlanned;
  const hasChildren = childCount > 0;
  const canQuickEditStatus = item.type !== "phase" && !hasChildren && typeof onStatusChange === "function";
  const schedule = item.rollup?.schedule;
  const delayLabel = window.ConstructProData.formatScheduleDelayLabel(schedule);
  const planShiftDays = schedule?.planShiftDays || 0;
  const showPlanShift = Boolean(schedule?.hasPlanShift);
  const formatDate = window.ConstructProData.formatScheduleDate;
  const displayStart = item.startDate ? formatDate(item.startDate) : "—";
  const displayDue = item.dueDate ? formatDate(item.dueDate) : "—";
  const dateRange = `${displayStart} → ${displayDue}`;
  const indent = Math.min(item.level, isMobile ? 3 : 6) * (isMobile ? 10 : 14);

  const subtitleParts = [];
  if (item.type !== "phase" && blockName) subtitleParts.push(blockName);
  if (item.floor) subtitleParts.push(item.floor);
  if (item.assigneeRole) subtitleParts.push(item.assigneeRole);
  subtitleParts.push(dateRange);
  if (hasChildren) subtitleParts.push(`${childCount} nested`);

  const renderActions = () => {
    if (item.type === "phase") {
      const isBlock = !item.parentId;
      if (isBlock) {
        return (
          <>
            <RowAddControl
              label="Add"
              compact
              ariaLabel="Add phase or task to this block"
              options={[
                { label: "Phase / Work Type", onClick: () => onAddChild("phase") },
                { label: "Task", onClick: () => onAddChild("task") }
              ]}
            />
          </>
        );
      }
      return (
        <>
          <RowAddControl
            label="Add task"
            compact
            ariaLabel="Add a new task to this phase"
            onClick={(event) => {
              event.stopPropagation();
              onAddChild("task");
            }}
          />
          <RowActionMenu onEdit={onEdit} onDelete={onDelete} />
        </>
      );
    }
    if (item.type === "task") {
      return (
        <>
          <RowAddControl
            label="Subtask / QC"
            compact
            ariaLabel="Add subtask or QC check under this task"
            options={[
              { label: "Subtask", onClick: () => onAddChild("subtask") },
              { label: "QC check", onClick: () => onAddChild("qc") }
            ]}
          />
          <RowActionMenu onEdit={onEdit} onDelete={onDelete} />
        </>
      );
    }
    return <RowActionMenu onEdit={onEdit} onDelete={onDelete} />;
  };

  const progressTone = status === "done" || status === "approved" ? "success" : status === "blocked" ? "danger" : "orange";

  return (
    <div
      className={`work-item-row work-item-row--${typeMeta.modifier} ${selected ? "work-item-row--selected" : ""} ${isMobile ? "work-item-row--mobile" : ""}`}
      draggable={false}
    >
      <div className="work-item-row__main" style={{ paddingLeft: indent }}>
        <span className="work-item-row__spacer" aria-hidden="true" />
        {hasChildren ? (
          <button
            type="button"
            onClick={(event) => {
              event.stopPropagation();
              onToggleCollapse();
            }}
            className="work-item-row__toggle"
            aria-label={isCollapsed ? "Expand children" : "Collapse children"}
          >
            {isCollapsed ? "›" : "▾"}
          </button>
        ) : (
          <span className="work-item-row__spacer" aria-hidden="true" />
        )}
        <div
          className="work-item-row__content"
          role="button"
          tabIndex={0}
          onClick={onSelect}
          onKeyDown={(event) => {
            if (event.key === "Enter" || event.key === " ") {
              event.preventDefault();
              onSelect();
            }
          }}
        >
          <div className="work-item-row__title-row">
            <span className={`work-item-type-tag work-item-type-tag--${typeMeta.modifier}`}>{typeMeta.label}</span>
            <p className="work-item-row__title">{item.title}</p>
            {delayLabel ? (
              <span className={`work-item-delay-chip work-item-delay-chip--${schedule?.status || "delayed"}`} title={schedule?.daysLate ? `${schedule.daysLate} day${schedule.daysLate === 1 ? "" : "s"} past due date` : "Progress behind planned schedule"}>
                {delayLabel}
              </span>
            ) : null}
            {showPlanShift ? (
              <span
                className={`work-item-delay-chip work-item-delay-chip--${planShiftDays > 0 ? "delayed" : "at_risk"}`}
                title={`Planned dates moved ${planShiftDays > 0 ? `+${planShiftDays}` : planShiftDays} day(s) from the original estimate`}
              >
                {planShiftDays > 0 ? `Plan +${planShiftDays}d` : `Plan ${planShiftDays}d`}
              </span>
            ) : null}
          </div>
          <p className="work-item-row__subtitle">{subtitleParts.join(" · ")}</p>
          {dependencies?.totalLinks > 0 ? (
            <WorkItemDependencyInline
              dependencies={dependencies}
              onFocus={onFocusDependency}
            />
          ) : null}
        </div>
      </div>

      <div className="work-item-row__metrics-wrap">
        <div className="work-item-row__budget-col" data-label="Budget">
          {item.type !== "phase" ? (
            <span className="work-item-metric__value">{ff(budget || 0)}</span>
          ) : null}
        </div>

        <div className="work-item-row__status-col" data-label="Status">
          <RowStatusPicker
            status={item.status}
            statusLabel={statusLabel}
            tone={statusTone(status)}
            readOnly={!canQuickEditStatus}
            readOnlyTitle={hasChildren ? "Status rolls up from subtasks" : undefined}
            onChange={canQuickEditStatus ? onStatusChange : undefined}
          />
        </div>

        <div className="work-item-row__progress-col" data-label="Progress">
          <div className="work-item-row__progress-track">
            <ProgressBar value={progress} tone={progressTone} />
          </div>
          <span className="work-item-row__progress-value">{progressDisplay}</span>
        </div>
      </div>

      <div className="work-item-row__actions-col" data-label="Actions" onClick={(event) => event.stopPropagation()}>
        {renderActions()}
      </div>
    </div>
  );
}

function WorkItemDetail({
  item,
  embedded = false,
  onClose,
  onDelete,
  onEdit,
  childCount = 0,
  detailIntent = null,
  dependencies = null,
  onFocusTask
}) {
  const [activeTab, setActiveTab] = React.useState("general");
  const [note, setNote] = React.useState("");
  const [status, setStatus] = React.useState(item.status);
  const [confirmDelete, setConfirmDelete] = React.useState(false);

  const [showDprForm, setShowDprForm] = React.useState(false);
  const [dprComment, setDprComment] = React.useState("");
  const [dprLaborCount, setDprLaborCount] = React.useState(item.labor?.estCount || 10);
  const [dprLaborCost, setDprLaborCost] = React.useState((item.labor?.estDailyCost) || 3000);
  const [dprMaterials, setDprMaterials] = React.useState(() => {
    return (item.materials || []).map(m => ({ name: m.name, quantity: 0, cost: 0 }));
  });

  React.useEffect(() => {
    setNote("");
    setStatus(item.status);
    setShowDprForm(false);
    setConfirmDelete(false);
    setDprComment("");
    setDprLaborCount(item.labor?.estCount || 10);
    setDprLaborCost(item.labor?.estDailyCost || 3000);
    setDprMaterials((item.materials || []).map(m => ({ name: m.name, quantity: 0, cost: 0 })));
  }, [item.id, item.status, item.progressPct]);

  React.useEffect(() => {
    if (!detailIntent) return;
    if (detailIntent.tab) setActiveTab(detailIntent.tab);
    if (detailIntent.openDpr) setShowDprForm(true);
    if (detailIntent.focusStatus) {
      window.requestAnimationFrame(() => document.getElementById("detail-status")?.focus());
    }
  }, [detailIntent, item.id]);

  const submitDpr = (e) => {
    if (e) e.preventDefault();
    const materialsUsed = dprMaterials.map(dm => {
      const match = (item.materials || []).find(m => m.name === dm.name);
      const cost = dm.quantity * (match ? match.estUnitCost : 100);
      return { name: dm.name, quantity: Number(dm.quantity) || 0, cost };
    });

    window.ConstructProData.addDprEntry({
      workItemId: item.id,
      date: new Date().toISOString().slice(0, 10),
      comment: dprComment || "Daily progress update",
      laborCount: Number(dprLaborCount) || 0,
      laborCost: Number(dprLaborCost) || 0,
      materialsUsed
    });
    setShowDprForm(false);
    window.ConstructProData.showToast("DPR submitted successfully");
  };

  const handleMaterialQtyChange = (name, qty) => {
    setDprMaterials(prev => prev.map(m => m.name === name ? { ...m, quantity: Number(qty) || 0 } : m));
  };

  const ff = window.ConstructProData.formatCurrency;

  const statusLabel = window.ConstructProData.statuses.find((s) => s.id === (item.rollup?.status || item.status))?.label
    || item.rollup?.status || item.status;
  const progressValue = item.rollup?.progressPct ?? item.progressPct ?? 0;
  const subtaskProgress = item.rollup?.subtaskProgress;
  const progressDisplay = subtaskProgress?.total
    ? `${subtaskProgress.done}/${subtaskProgress.total} · ${progressValue}%`
    : `${progressValue}%`;
  const schedule = item.rollup?.schedule;
  const delayLabel = window.ConstructProData.formatScheduleDelayLabel(schedule);
  const formatDate = window.ConstructProData.formatScheduleDate;
  const itemSuggestions = React.useMemo(
    () => buildWorkItemSuggestions(item, dependencies),
    [item, dependencies]
  );

  const runSuggestionAction = (suggestion) => {
    if (suggestion.action === "focus_pred" && dependencies?.predecessors?.[0]?.id) {
      onFocusTask?.(dependencies.predecessors[0].id);
      return;
    }
    if (suggestion.action === "edit") {
      onEdit?.();
      return;
    }
    if (suggestion.action === "dpr") {
      setActiveTab("dpr");
      setShowDprForm(true);
      return;
    }
    if (suggestion.action === "evidence") {
      window.ConstructProData.addEvidence({
        workItemId: item.id,
        by: "Admin",
        type: "Checklist",
        note: "QC evidence requested from suggestions.",
        checklistComplete: false
      });
      window.ConstructProData.showToast("Add photos or checklist details in Evidence.");
      return;
    }
    setActiveTab("general");
    document.getElementById("detail-status")?.focus();
  };

  const body = (
    <>
      {embedded ? (
        <div className="task-preview-summary mb-4 grid grid-cols-2 gap-3 sm:grid-cols-4">
          <div className="task-preview-summary__stat">
            <span className="task-preview-summary__label">Status</span>
            <Badge tone={statusTone(item.rollup?.status || item.status)}>{statusLabel}</Badge>
          </div>
          <div className="task-preview-summary__stat">
            <span className="task-preview-summary__label">Progress</span>
            <span className="task-preview-summary__value">{progressDisplay}</span>
          </div>
          <div className="task-preview-summary__stat">
            <span className="task-preview-summary__label">Budget</span>
            <span className="task-preview-summary__value">{ff(item.rollup?.budgetPlanned || item.budgetPlanned || 0)}</span>
          </div>
          <div className="task-preview-summary__stat">
            <span className="task-preview-summary__label">Schedule</span>
            {delayLabel ? (
              <span className={`work-item-delay-chip work-item-delay-chip--${schedule?.status || "delayed"}`}>{delayLabel}</span>
            ) : (
              <span className="task-preview-summary__value text-success">On track</span>
            )}
          </div>
        </div>
      ) : (
        <SectionTitle title="Task Command Center" subtitle={item.title} />
      )}

      <div className="flex border-b border-border-light mb-4">
        {["general", "resources", "dpr"].map((tab) => (
          <button
            key={tab}
            type="button"
            className={`flex-1 py-2 text-xs font-bold uppercase tracking-wider transition-colors border-b-2 ${activeTab === tab ? "border-primary text-primary" : "border-transparent text-text-muted hover:text-text-primary"}`}
            onClick={() => setActiveTab(tab)}
          >
            {tab === "general" ? "General" : tab === "resources" ? "Estimates" : "DPR Ledger"}
          </button>
        ))}
      </div>

      {activeTab === "general" && (
        <div className="space-y-4">
          {itemSuggestions.length ? (
            <TaskSuggestionsPanel
              compact
              suggestions={itemSuggestions}
              onSelect={(suggestion) => runSuggestionAction(suggestion)}
            />
          ) : null}

          <div className="grid grid-cols-2 gap-3 text-sm">
            <InfoPill label="Type" value={item.type} />
            <InfoPill label="Assignee" value={item.assigneeRole} />
            <InfoPill label="Floor" value={item.floor || "—"} />
            <InfoPill label="Block" value={item.blockName || item.location || "—"} />
            <InfoPill label="Planned Budget" value={ff(item.rollup?.budgetPlanned || item.budgetPlanned)} />
            <InfoPill label="Actual Expenses" value={ff(item.rollup?.budgetActual || item.budgetActual)} />
          </div>

          <TaskSchedulePanel
            schedule={schedule}
            plannedStart={item.startDate}
            plannedDue={item.dueDate}
            formatDate={formatDate}
            delayLabel={delayLabel}
          />

          <TaskDependenciesPanel
            item={item}
            dependencies={dependencies}
            onFocusTask={onFocusTask}
            onEdit={onEdit}
          />

          {!showDprForm ? (
            <div className="space-y-3">
              <div className="rounded-xl border border-border-light bg-surface-container-low p-3">
                <div className="mb-2 flex items-center justify-between gap-2">
                  <span className="text-xs font-bold uppercase tracking-wider text-text-muted">Progress</span>
                  <span className="text-sm font-bold text-text-primary tabular-nums">{progressDisplay}</span>
                </div>
                <ProgressBar
                  value={progressValue}
                  tone={status === "done" || status === "approved" ? "success" : status === "blocked" ? "danger" : "orange"}
                />
                <p className="mt-2 text-xs text-text-muted">Derived from field updates, DPR spend, and status.</p>
              </div>

              <SelectField id="detail-status" label="Status" value={status} onChange={setStatus}>
                {window.ConstructProData.statuses.map((itemStatus) => <option key={itemStatus.id} value={itemStatus.id}>{itemStatus.label}</option>)}
              </SelectField>
              <label className="block" htmlFor="detail-note">
                <span className="mb-1 block text-xs font-bold uppercase tracking-wider text-text-muted">Comment / evidence note</span>
                <textarea id="detail-note" value={note} onChange={(event) => setNote(event.target.value)} className="min-h-16 w-full rounded-lg border border-border-light px-3 py-2 text-sm transition-colors focus:border-cta" />
              </label>

              <div className="work-item-detail-actions space-y-2">
                <Button className="w-full" onClick={() => {
                  window.ConstructProData.updateWorkStatus({
                    workItemId: item.id,
                    status,
                    note,
                    role: "Admin"
                  });
                  window.ConstructProData.showToast("Progress updated successfully");
                }}>Update Status</Button>
                <div className="grid grid-cols-2 gap-2">
                  <Button variant="secondary" className="w-full" onClick={() => setShowDprForm(true)}><Icons.plus /> Daily DPR</Button>
                  <Button variant="secondary" className="w-full" onClick={() => {
                    window.ConstructProData.addEvidence({
                      workItemId: item.id,
                      by: "Admin",
                      type: "Checklist",
                      note,
                      checklistComplete: true
                    });
                    window.ConstructProData.showToast("Evidence added successfully");
                  }}><Icons.camera /> Add Evidence</Button>
                </div>
              </div>
            </div>
          ) : (
            <form onSubmit={submitDpr} className="rounded-xl border border-primary/20 bg-primary-fixed/10 p-4 space-y-3 fade-in">
              <div className="flex items-center justify-between border-b border-border-light pb-2">
                <h4 className="font-bold text-sm text-primary">Submit Daily Progress Report (DPR)</h4>
                <button type="button" onClick={() => setShowDprForm(false)} className="text-text-muted hover:text-text-primary text-sm font-bold">&times; Close</button>
              </div>

              <div className="grid grid-cols-2 gap-3">
                <InputField id="dpr-lab" label="Labour count today" type="number" value={dprLaborCount} onChange={setDprLaborCount} required />
                <InputField id="dpr-lab-cost" label="Labour cost today (₹)" type="number" value={dprLaborCost} onChange={setDprLaborCost} required />
              </div>
              <p className="text-xs text-text-muted">
                Progress recalculates from cumulative spend vs planned budget ({progressValue}% now).
              </p>

              {dprMaterials.length > 0 && (
                <div className="border-t border-border-light pt-2 space-y-2">
                  <p className="text-[10px] font-bold uppercase tracking-wider text-text-muted">Material Consumed Today:</p>
                  <div className="grid grid-cols-1 gap-2">
                    {dprMaterials.map(dm => {
                      const orig = (item.materials || []).find(m => m.name === dm.name);
                      return (
                        <div key={dm.name} className="flex items-center justify-between gap-3 text-xs">
                          <span className="font-bold text-text-primary">{dm.name} ({orig?.unit}):</span>
                          <input
                            type="number"
                            placeholder="Qty used"
                            value={dm.quantity || ""}
                            onChange={(e) => handleMaterialQtyChange(dm.name, e.target.value)}
                            className="w-24 rounded border border-border-light px-2 py-1 text-xs"
                          />
                        </div>
                      );
                    })}
                  </div>
                </div>
              )}

              <label className="block">
                <span className="mb-1 block text-xs font-bold uppercase tracking-wider text-text-muted">DPR Notes</span>
                <textarea value={dprComment} onChange={(e) => setDprComment(e.target.value)} placeholder="Work notes..." className="min-h-12 w-full rounded-lg border border-border-light px-3 py-2 text-xs transition-colors focus:border-cta" />
              </label>

              <Button className="w-full" type="submit">Submit Report</Button>
            </form>
          )}

          <div className="mt-4 border-t border-border-light pt-3">
            <p className="mb-2 text-xs font-bold uppercase tracking-wider text-text-muted">Recent Comments</p>
            <div className="space-y-2">
              {(item.comments || []).slice(0, 3).map((comment) => (
                <div key={comment.id} className="rounded-lg bg-gray-50 p-2.5 text-xs">
                  <b>{comment.by}</b> <span className="text-text-muted">· {window.ConstructProData.formatTime(comment.createdAt)}</span>
                  <p className="mt-1 text-text-muted">{comment.note}</p>
                </div>
              ))}
              {!item.comments?.length && <p className="text-xs text-text-muted italic">No comments yet.</p>}
            </div>
          </div>

          {onDelete ? (
            <div className="work-item-detail-danger">
              {!confirmDelete ? (
                <button
                  type="button"
                  className="work-item-detail-danger__trigger"
                  onClick={() => setConfirmDelete(true)}
                >
                  Delete work item…
                </button>
              ) : (
                <div className="work-item-detail-danger__confirm">
                  <p className="work-item-detail-danger__message">
                    Delete <strong>{item.title}</strong>
                    {childCount ? ` and ${childCount} nested item${childCount === 1 ? "" : "s"}` : ""}?
                    This cannot be undone.
                  </p>
                  <div className="work-item-detail-danger__actions">
                    <Button variant="secondary" type="button" onClick={() => setConfirmDelete(false)}>Cancel</Button>
                    <Button
                      variant="danger"
                      type="button"
                      onClick={() => onDelete(item)}
                    >
                      Delete permanently
                    </Button>
                  </div>
                </div>
              )}
            </div>
          ) : null}
        </div>
      )}

      {activeTab === "resources" && (
        <div className="space-y-4">
          <div className="rounded-xl border border-border-light bg-slate-50 p-3">
            <h4 className="font-bold text-xs uppercase tracking-wider text-text-muted mb-2">Labour Resource Planning</h4>
            <div className="grid grid-cols-2 gap-4 text-xs">
              <div>
                <span className="text-text-muted block">Planned Workforce:</span>
                <b className="text-sm font-bold text-text-primary">{item.labor?.estCount || 0} Workers</b>
              </div>
              <div>
                <span className="text-text-muted block">Planned Daily Rate:</span>
                <b className="text-sm font-bold text-text-primary">{ff(item.labor?.estDailyCost || 0)}</b>
              </div>
              <div>
                <span className="text-text-muted block">Actual Workforce:</span>
                <b className="text-sm font-bold text-success">{item.labor?.actualCount || 0} Workers</b>
              </div>
              <div>
                <span className="text-text-muted block">Actual Daily Rate:</span>
                <b className="text-sm font-bold text-success">{ff(item.labor?.actualDailyCost || 0)}</b>
              </div>
            </div>
          </div>

          <div className="rounded-xl border border-border-light bg-white p-3">
            <h4 className="font-bold text-xs uppercase tracking-wider text-text-muted mb-2">Materials Planning</h4>
            <div className="space-y-3">
              {(item.materials || []).map((m) => {
                const estTotal = m.quantity * m.estUnitCost;
                const actTotal = (m.actualQuantity || 0) * (m.actualUnitCost || m.estUnitCost);
                const progress = m.quantity > 0 ? Math.round(((m.actualQuantity || 0) / m.quantity) * 100) : 0;
                return (
                  <div key={m.name} className="text-xs border-b border-border-light pb-2 last:border-b-0">
                    <div className="flex items-center justify-between font-bold mb-1">
                      <span className="text-text-primary">{m.name}</span>
                      <span className={m.allocatedQty >= m.quantity ? "text-success" : "text-warning"}>
                        Allocated: {m.allocatedQty || 0} / {m.quantity} {m.unit}
                      </span>
                    </div>
                    <div className="grid grid-cols-2 gap-2 text-text-muted">
                      <div>
                        Planned: <b className="text-text-primary">{m.quantity} {m.unit}</b> ({ff(estTotal)})
                      </div>
                      <div>
                        Actual: <b className="text-success">{m.actualQuantity || 0} {m.unit}</b> ({ff(actTotal)})
                      </div>
                    </div>
                    <ProgressBar value={progress} tone={progress > 100 ? "danger" : "orange"} />
                  </div>
                );
              })}
              {(!item.materials || item.materials.length === 0) && (
                <p className="text-xs text-text-muted italic">No materials assigned to this task.</p>
              )}
            </div>
          </div>
        </div>
      )}

      {activeTab === "dpr" && (
        <div className="space-y-3">
          <h4 className="font-bold text-xs uppercase tracking-wider text-text-muted mb-2">Daily Progress Reports</h4>
          <div className="space-y-3 max-h-80 overflow-y-auto pr-1">
            {(item.dprHistory || []).map((log) => {
              const materialsCost = log.materialsUsed?.reduce((sum, m) => sum + (m.cost || 0), 0) || 0;
              const totalCost = log.laborCost + materialsCost;
              return (
                <div key={log.id} className="rounded-xl border border-border-light bg-white p-3 space-y-2 text-xs shadow-sm">
                  <div className="flex items-center justify-between border-b border-border-light pb-1 font-bold">
                    <span className="text-text-primary">{log.date}</span>
                    <Badge tone="success">{log.progressPct}% Progress</Badge>
                  </div>
                  <p className="text-text-muted italic">{log.comment}</p>
                  <div className="grid grid-cols-2 gap-2 border-t border-border-light/50 pt-2 text-[11px] text-text-muted">
                    <div>
                      Workforce: <b className="text-text-primary">{log.laborCount} Present</b>
                    </div>
                    <div>
                      Labour Outlay: <b className="text-text-primary">{ff(log.laborCost)}</b>
                    </div>
                    <div className="col-span-2">
                      Materials consumed cost: <b className="text-text-primary">{ff(materialsCost)}</b>
                    </div>
                    <div className="col-span-2 text-right font-bold text-primary">
                      Outlay: {ff(totalCost)}
                    </div>
                  </div>
                  {log.materialsUsed?.length > 0 && (
                    <div className="bg-slate-50 rounded-lg p-2 mt-1">
                      <span className="text-[10px] text-text-muted font-bold block mb-1">Materials Used:</span>
                      {log.materialsUsed.map(m => (
                        <div key={m.name} className="flex justify-between text-[10px]">
                          <span>{m.name}</span>
                          <b>{m.quantity} Units ({ff(m.cost)})</b>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              );
            })}
            {(!item.dprHistory || item.dprHistory.length === 0) && (
              <p className="text-xs text-text-muted italic text-center py-4">No daily reports recorded yet.</p>
            )}
          </div>
        </div>
      )}
    </>
  );

  if (embedded) return body;
  return <Card>{body}</Card>;
}

const SUGGESTION_TONE_ORDER = { danger: 0, warning: 1, info: 2 };

function buildWorkItemSuggestions(item, dependencies = null) {
  if (!item || item.type === "phase") return [];
  if ((item.rollup?.childCount || 0) > 0) return [];

  const suggestions = [];
  const schedule = item.rollup?.schedule;
  const delayLabel = window.ConstructProData.formatScheduleDelayLabel(schedule);

  if (dependencies?.waitingOnIncomplete) {
    const pending = dependencies.predecessors.filter((pred) => !pred.complete);
    suggestions.push({
      id: "dependency-waiting",
      tone: "warning",
      title: "Waiting on predecessor",
      message: pending.length === 1
        ? `This task starts after “${pending[0].title}” is complete.`
        : `This task is blocked until ${pending.length} predecessor tasks finish.`,
      action: "focus_pred",
      cta: "View dependency"
    });
  }

  if (schedule?.status === "delayed") {
    suggestions.push({
      id: "schedule-delayed",
      tone: "danger",
      title: delayLabel || "Delayed",
      message: schedule.daysLate > 0
        ? "Due date passed — revise dates or mark blocked if waiting on dependency."
        : "Progress is behind plan — log a DPR or update status.",
      action: schedule.daysLate > 0 ? "edit" : "dpr",
      cta: schedule.daysLate > 0 ? "Edit dates" : "Submit DPR"
    });
  } else if (schedule?.status === "at_risk") {
    suggestions.push({
      id: "schedule-at-risk",
      tone: "warning",
      title: "Behind schedule",
      message: "Field progress is slipping — submit today's DPR before delay grows.",
      action: "dpr",
      cta: "Submit DPR"
    });
  }

  if (item.status === "blocked") {
    suggestions.push({
      id: "status-blocked",
      tone: "danger",
      title: "Blocked",
      message: "Document the blocker in a comment, then update status when cleared.",
      action: "status",
      cta: "Update status"
    });
  }

  if (item.status === "review") {
    suggestions.push({
      id: "status-review",
      tone: "warning",
      title: "Awaiting review",
      message: "Verify work on site and move to Done or back to In Progress.",
      action: "status",
      cta: "Review status"
    });
  }

  if (item.type === "qc" && !(item.evidence || []).length) {
    suggestions.push({
      id: "qc-evidence",
      tone: "info",
      title: "QC evidence missing",
      message: "Attach photos or checklist proof before sign-off.",
      action: "evidence",
      cta: "Add evidence"
    });
  }

  if (item.status === "todo" && (schedule?.plannedPct || 0) > 0) {
    suggestions.push({
      id: "should-start",
      tone: "info",
      title: "Should have started",
      message: "Move to In Progress or adjust the start date in Edit.",
      action: "edit",
      cta: "Edit task"
    });
  }

  return suggestions;
}

function collectProjectTaskSuggestions(flatTree, limit = 4) {
  const rows = [];
  flatTree.forEach((item) => {
    buildWorkItemSuggestions(item).forEach((suggestion) => {
      rows.push({
        ...suggestion,
        workItemId: item.id,
        workItemTitle: item.title,
        workItemType: item.type
      });
    });
  });
  return rows.sort((a, b) => {
    const toneDiff = (SUGGESTION_TONE_ORDER[a.tone] ?? 9) - (SUGGESTION_TONE_ORDER[b.tone] ?? 9);
    if (toneDiff !== 0) return toneDiff;
    return a.workItemTitle.localeCompare(b.workItemTitle);
  }).slice(0, limit);
}

function TaskSuggestionsPanel({ suggestions, onSelect, compact = false }) {
  if (!suggestions.length) return null;

  return (
    <section className={`task-suggestions${compact ? " task-suggestions--compact" : ""}`} aria-label="Task suggestions">
      <div className="task-suggestions__header">
        <span className="task-suggestions__icon" aria-hidden="true"><Icons.tips size={18} /></span>
        <div>
          <h3 className="task-suggestions__title">{compact ? "Suggested next steps" : "Suggestions"}</h3>
          {!compact ? (
            <p className="task-suggestions__subtitle">Actionable items based on schedule, status, and QC gaps.</p>
          ) : null}
        </div>
      </div>
      <ul className="task-suggestions__list">
        {suggestions.map((suggestion) => (
          <li key={`${suggestion.workItemId || "item"}-${suggestion.id}`}>
            <button
              type="button"
              className={`task-suggestions__item task-suggestions__item--${suggestion.tone}`}
              onClick={() => onSelect(suggestion)}
            >
              <span className="task-suggestions__item-main">
                <span className="task-suggestions__item-title">
                  {suggestion.workItemTitle ? (
                    <>
                      <span className="task-suggestions__task-name">{suggestion.workItemTitle}</span>
                      <span className="task-suggestions__item-sep">·</span>
                    </>
                  ) : null}
                  {suggestion.title}
                </span>
                <span className="task-suggestions__item-message">{suggestion.message}</span>
              </span>
              <span className="task-suggestions__cta">{suggestion.cta || "Open"}</span>
            </button>
          </li>
        ))}
      </ul>
    </section>
  );
}

function normalizeProjectBlock(block) {
  if (typeof block === "string") return { id: "", name: block, floor: "", targetDays: 60 };
  return {
    id: block?.id || "",
    name: block?.name || "",
    floor: String(block?.floor || "").trim(),
    targetDays: Number(block?.targetDays || 60)
  };
}

function getProjectBlocks(snapshot, flatTree) {
  const fromProject = (snapshot.project?.blocks || [])
    .map(normalizeProjectBlock)
    .filter((block) => block.name);
  if (fromProject.length) return fromProject;
  return flatTree
    .filter((item) => item.type === "phase")
    .map((item) => ({ name: item.title, floor: item.floor || "", targetDays: 60 }));
}

function resolveBlockName(item, itemById, blockRootNames = new Set()) {
  if (item.blockName) return item.blockName;
  if (item.type === "phase" && blockRootNames.has(item.title)) return item.title;
  if (item.location && blockRootNames.has(item.location)) return item.location;
  let parentId = item.parentId;
  while (parentId && itemById) {
    const parent = itemById.get(parentId);
    if (!parent) break;
    if (parent.blockName) return parent.blockName;
    if (parent.type === "phase" && blockRootNames.has(parent.title)) return parent.title;
    if (parent.location && blockRootNames.has(parent.location)) return parent.location;
    parentId = parent.parentId;
  }
  return "";
}

function buildDependentsIndex(flatTree) {
  const index = new Map();
  flatTree.forEach((item) => {
    if (!window.WorkPlanEditor.isLinkableDependencyType(item.type)) return;
    (item.dependencies || []).forEach((predId) => {
      if (!index.has(predId)) index.set(predId, []);
      index.get(predId).push(item);
    });
  });
  return index;
}

function toDependencyNode(item, itemById, blockRootNames) {
  if (!item) return null;
  const status = item.rollup?.status || item.status;
  const progressPct = item.rollup?.progressPct ?? item.progressPct ?? 0;
  const complete = status === "done" || status === "approved" || progressPct >= 100;
  return {
    id: item.id,
    title: item.title,
    type: item.type,
    blockName: resolveBlockName(item, itemById, blockRootNames),
    status,
    progressPct,
    complete,
    scheduleStatus: item.rollup?.schedule?.status
  };
}

function getWorkItemDependencySummary(item, itemById, dependentsById, blockRootNames) {
  if (!item || !window.WorkPlanEditor.isLinkableDependencyType(item.type)) {
    return {
      predecessors: [],
      dependents: [],
      waitingOnIncomplete: false,
      blocksOthers: false,
      totalLinks: 0
    };
  }
  const predecessors = (item.dependencies || [])
    .map((id) => toDependencyNode(itemById.get(id), itemById, blockRootNames))
    .filter(Boolean);
  const dependents = (dependentsById.get(item.id) || [])
    .map((dep) => toDependencyNode(dep, itemById, blockRootNames))
    .filter(Boolean);
  const waitingOnIncomplete = predecessors.some((pred) => !pred.complete);
  return {
    predecessors,
    dependents,
    waitingOnIncomplete,
    blocksOthers: dependents.length > 0,
    totalLinks: predecessors.length + dependents.length
  };
}

function WorkItemDependencyInline({ dependencies, onFocus }) {
  const { predecessors, dependents, waitingOnIncomplete } = dependencies;
  const parts = [];

  if (predecessors.length) {
    const first = predecessors[0];
    const extra = predecessors.length > 1 ? ` +${predecessors.length - 1}` : "";
    parts.push(
      <button
        key={`pred-${first.id}`}
        type="button"
        className={`work-item-dependency-chip work-item-dependency-chip--after${waitingOnIncomplete ? " work-item-dependency-chip--waiting" : ""}`}
        onClick={(event) => {
          event.stopPropagation();
          onFocus?.(first.id);
        }}
        title={predecessors.map((pred) => pred.title).join(", ")}
      >
        <Icons.link size={12} className="shrink-0" aria-hidden="true" />
        <span>After {first.title}{extra}</span>
      </button>
    );
  }

  if (dependents.length) {
    const first = dependents[0];
    const extra = dependents.length > 1 ? ` +${dependents.length - 1}` : "";
    parts.push(
      <button
        key={`dep-${first.id}`}
        type="button"
        className="work-item-dependency-chip work-item-dependency-chip--blocks"
        onClick={(event) => {
          event.stopPropagation();
          onFocus?.(first.id);
        }}
        title={dependents.map((dep) => dep.title).join(", ")}
      >
        <span>Blocks {dependents.length === 1 ? first.title : `${dependents.length} tasks`}{extra}</span>
      </button>
    );
  }

  return <div className="work-item-dependency-inline">{parts}</div>;
}

function TaskDependenciesPanel({ item, dependencies, onFocusTask, onEdit }) {
  if (!item || !window.WorkPlanEditor.supportsDependencies(item.type)) return null;

  const { predecessors, dependents, waitingOnIncomplete } = dependencies || {
    predecessors: [],
    dependents: [],
    waitingOnIncomplete: false
  };
  const hasLinks = predecessors.length || dependents.length;

  return (
    <section className="task-dependencies-panel" aria-label="Task dependencies">
      <div className="task-dependencies-panel__header">
        <div>
          <span className="text-xs font-bold uppercase tracking-wider text-text-muted">Dependencies</span>
          {waitingOnIncomplete ? (
            <p className="task-dependencies-panel__alert">
              <Icons.warningAmber size={14} aria-hidden="true" />
              Waiting for predecessor to finish
            </p>
          ) : null}
        </div>
        {hasLinks ? (
          <span className="task-dependencies-panel__count">
            {predecessors.length + dependents.length} link{(predecessors.length + dependents.length) === 1 ? "" : "s"}
          </span>
        ) : null}
      </div>

      {!hasLinks ? (
        <div className="task-dependencies-panel__empty">
          <Icons.linkOff size={20} className="text-text-muted" aria-hidden="true" />
          <p>No sequence links yet.</p>
          <button type="button" className="task-dependencies-panel__edit-link" onClick={onEdit}>
            Add dependency in editor
          </button>
        </div>
      ) : (
        <div className="task-dependencies-panel__groups">
          {predecessors.length ? (
            <div className="task-dependencies-panel__group">
              <p className="task-dependencies-panel__group-label">Starts after</p>
              <ul className="task-dependencies-panel__list">
                {predecessors.map((pred) => (
                  <li key={pred.id}>
                    <DependencyLinkCard node={pred} direction="predecessor" onFocus={onFocusTask} />
                  </li>
                ))}
              </ul>
            </div>
          ) : null}
          {dependents.length ? (
            <div className="task-dependencies-panel__group">
              <p className="task-dependencies-panel__group-label">Blocks next</p>
              <ul className="task-dependencies-panel__list">
                {dependents.map((dep) => (
                  <li key={dep.id}>
                    <DependencyLinkCard node={dep} direction="dependent" onFocus={onFocusTask} />
                  </li>
                ))}
              </ul>
            </div>
          ) : null}
        </div>
      )}
    </section>
  );
}

function DependencyLinkCard({ node, direction, onFocus }) {
  const statusLabel = window.WorkPlanEditor.formatWorkStatus(node.status);
  const tone = node.complete ? "success" : node.scheduleStatus === "delayed" ? "danger" : "info";

  return (
    <button
      type="button"
      className={`dependency-link-card dependency-link-card--${direction}${node.complete ? " dependency-link-card--complete" : ""}`}
      onClick={() => onFocus?.(node.id)}
    >
      <span className="dependency-link-card__flow" aria-hidden="true">
        {direction === "predecessor" ? "←" : "→"}
      </span>
      <span className="dependency-link-card__body">
        <span className="dependency-link-card__meta">
          {node.blockName ? <span className="dependency-link-card__block">{node.blockName}</span> : null}
          <span className="dependency-link-card__type">{node.type}</span>
        </span>
        <span className="dependency-link-card__title">{node.title}</span>
      </span>
      <span className="dependency-link-card__status">
        <Badge tone={tone} className="dependency-link-card__badge">{node.complete ? "Done" : `${node.progressPct}%`}</Badge>
        <span className="dependency-link-card__status-label">{statusLabel}</span>
      </span>
      <Icons.chevronRight size={18} className="dependency-link-card__chevron" aria-hidden="true" />
    </button>
  );
}

function buildDirectChildCountMap(flatTree) {
  const map = new Map();
  flatTree.forEach((item) => {
    if (!item.parentId) return;
    map.set(item.parentId, (map.get(item.parentId) || 0) + 1);
  });
  return map;
}

function buildDescendantCountMap(flatTree) {
  const counts = new Map(flatTree.map((item) => [item.id, 0]));
  [...flatTree].sort((a, b) => b.level - a.level).forEach((item) => {
    if (!item.parentId) return;
    counts.set(item.parentId, (counts.get(item.parentId) || 0) + 1 + (counts.get(item.id) || 0));
  });
  return counts;
}

function flattenWorkTree(nodes) {
  return nodes.flatMap((node) => [node, ...flattenWorkTree(node.children || [])]);
}

function statusTone(status) {
  if (status === "done" || status === "approved") return "success";
  if (status === "blocked") return "danger";
  if (status === "review") return "warning";
  if (status === "in_progress") return "info";
  return "neutral";
}

function InputField({ id, label, value, onChange, type = "text", required = false, placeholder = "" }) {
  return (
    <label htmlFor={id}>
      <span className="mb-1 block text-xs font-bold uppercase tracking-wider text-text-muted">{label}</span>
      <input id={id} type={type} inputMode={type === "number" ? "numeric" : undefined} required={required} value={value} placeholder={placeholder} onChange={(event) => onChange(event.target.value)} className="w-full rounded-lg border border-border-light px-3 py-2 transition-colors focus:border-cta" />
    </label>
  );
}

function SelectField({ id, label, value, onChange, children }) {
  return (
    <label htmlFor={id}>
      <span className="mb-1 block text-xs font-bold uppercase tracking-wider text-text-muted">{label}</span>
      <select id={id} value={value} onChange={(event) => onChange(event.target.value)} className="w-full rounded-lg border border-border-light px-3 py-2 transition-colors focus:border-cta">
        {children}
      </select>
    </label>
  );
}

function InfoPill({ label, value }) {
  return (
    <div className="rounded-xl bg-gray-50 p-3">
      <p className="text-xs font-bold uppercase text-text-muted">{label}</p>
      <p className="mt-1 font-bold">{value}</p>
    </div>
  );
}

function TaskSchedulePanel({ schedule, plannedStart: itemPlannedStart, plannedDue: itemPlannedDue, formatDate, delayLabel }) {
  const plannedStart = itemPlannedStart || schedule?.plannedStart || schedule?.startDate;
  const plannedDue = itemPlannedDue || schedule?.plannedDue || schedule?.dueDate;
  const baselineStart = schedule?.baselineStart;
  const baselineDue = schedule?.baselineDue;
  const planShiftDays = schedule?.planShiftDays || 0;
  const actualStart = schedule?.actualStart;
  const actualEnd = schedule?.actualEnd;
  const expectedStart = schedule?.expectedStart;
  const expectedDue = schedule?.expectedDue;
  const cascadeDays = schedule?.cascadeDelayDays || 0;
  const hasDates = plannedStart || plannedDue;

  if (!hasDates) {
    return (
      <div className="task-schedule-panel task-schedule-panel--empty">
        <p className="text-xs text-text-muted italic">No schedule dates set for this task.</p>
      </div>
    );
  }

  const actualStartLabel = actualStart ? formatDate(actualStart) : "Not started";
  const actualEndLabel = actualEnd
    ? formatDate(actualEnd)
    : actualStart
      ? "In progress"
      : "—";
  const showExpected = cascadeDays > 0 || (expectedDue && expectedDue !== plannedDue) || (expectedStart && expectedStart !== plannedStart);
  const planMoved = Boolean(schedule?.hasPlanShift);

  return (
    <div className="task-schedule-panel">
      <div className="task-schedule-panel__header">
        <span className="text-xs font-bold uppercase tracking-wider text-text-muted">Schedule</span>
        {delayLabel ? (
          <span className={`work-item-delay-chip work-item-delay-chip--${schedule?.status || "delayed"}`}>{delayLabel}</span>
        ) : planMoved ? (
          <span className={`work-item-delay-chip work-item-delay-chip--${planShiftDays > 0 ? "delayed" : "at_risk"}`}>
            {planShiftDays > 0 ? `Plan +${planShiftDays}d` : `Plan ${planShiftDays}d`}
          </span>
        ) : (
          <span className="text-xs font-semibold text-success">On track</span>
        )}
      </div>

      <div className="task-schedule-panel__grid">
        {planMoved ? (
          <div className="task-schedule-panel__block">
            <p className="task-schedule-panel__block-title">Baseline (estimate)</p>
            <ScheduleDateRow label="Start" value={formatDate(baselineStart)} muted />
            <ScheduleDateRow label="Due" value={formatDate(baselineDue)} muted />
          </div>
        ) : null}
        <div className="task-schedule-panel__block">
          <p className="task-schedule-panel__block-title">{planMoved ? "Revised plan" : "Planned"}</p>
          <ScheduleDateRow label="Start" value={formatDate(plannedStart)} />
          <ScheduleDateRow label="Due" value={formatDate(plannedDue)} />
        </div>
        <div className="task-schedule-panel__block">
          <p className="task-schedule-panel__block-title">Actual</p>
          <ScheduleDateRow label="Start" value={actualStartLabel} muted={!actualStart} />
          <ScheduleDateRow label="End" value={actualEndLabel} muted={!actualEnd && !actualStart} />
        </div>
      </div>

      {planMoved ? (
        <p className="task-schedule-panel__forecast-note">
          Plan dates revised from the original estimate
          {planShiftDays ? ` (${planShiftDays > 0 ? `+${planShiftDays}` : planShiftDays} day${Math.abs(planShiftDays) === 1 ? "" : "s"} on due date)` : ""}.
          Following tasks shifted automatically when the sequence changes.
        </p>
      ) : null}

      {showExpected ? (
        <div className="task-schedule-panel__forecast">
          <p className="task-schedule-panel__forecast-title">
            <Icons.schedule size={14} />
            Revised date (after upstream delays)
          </p>
          <div className="task-schedule-panel__forecast-dates">
            <span>{formatDate(expectedStart || plannedStart)} → {formatDate(expectedDue || plannedDue)}</span>
            {cascadeDays > 0 ? (
              <span className="task-schedule-panel__forecast-shift">+{cascadeDays}d from predecessors</span>
            ) : null}
          </div>
          <p className="task-schedule-panel__forecast-note">
            When an earlier task or subtask runs late, downstream dates shift automatically.
          </p>
        </div>
      ) : null}
    </div>
  );
}

function ScheduleDateRow({ label, value, muted = false }) {
  return (
    <div className="task-schedule-panel__row">
      <span className="task-schedule-panel__row-label">{label}</span>
      <span className={`task-schedule-panel__row-value${muted ? " task-schedule-panel__row-value--muted" : ""}`}>{value}</span>
    </div>
  );
}

Object.assign(window, { WorkItems });
