// consequence-class.jsx — клас наслідків як рухоме поле об'єкта + неруйнівне до-налаштування // Демонструє логіку, узгоджену в чаті: // • клас попередній (із Завдання) → уточнюється розрахунком (в обидва боки) // • обсяг експертизи ВИВОДИТЬСЯ з класу (а не зашитий у шаблон) // • зміна класу не перестворює проєкт, а пропонує ДЕЛЬТУ і зберігає зроблене // ---- Дельта складу робіт між двома обсягами експертизи ---- window.expertiseDelta = function (oldScope, newScope) { const stageOf = (sc) => window.getStageTemplate(window.EXPERTISE_STAGE_FOR_SCOPE[sc]); const oldIds = (oldScope && stageOf(oldScope)?.taskTemplateIds) || []; const newIds = (newScope && stageOf(newScope)?.taskTemplateIds) || []; const added = newIds.filter(id => !oldIds.includes(id)).map(window.getTaskTemplate).filter(Boolean); const removed = oldIds.filter(id => !newIds.includes(id)).map(window.getTaskTemplate).filter(Boolean); return { added, removed }; }; // ===================================================================== // ПАНЕЛЬ КЛАСУ НАСЛІДКІВ — у розгорнутій картці об'єкта // ===================================================================== function ConsequenceClassPanel({ obj, onRefine }) { const history = obj.gradeHistory || [{ value: obj.grade, kind: "preliminary", date: "", by: "", basis: "—" }]; const last = history[history.length - 1]; const kind = obj.gradeKind || last.kind || "preliminary"; const scope = obj.expertiseScope; const scopeLabel = window.EXPERTISE_SCOPE_LABELS[scope]?.full || "—"; const isSchema = obj.workType === "schema"; const kindMeta = kind === "calculated" ? { label: "Уточнений розрахунком", tone: "live" } : { label: "Попередній — із Завдання на проєктування", tone: "warn" }; if (isSchema) { return (