gantt-renderer 0.12.3 → 0.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -9
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["_exhaustive","toTask","MIN_PANE_WIDTH","#container","#opts","#dragOriginals","#scale","#callbacks","#taskIndex","#locale","#columns","#showAddTaskButton","#syncActionsColumnVisibility","#leftPaneDefaultWidth","#height","#timelineMinWidth","#weekendDays","#specialDaysByDate","#expandedIds","#cbs","#buildCallbackAdapter","#buildDom","#wireEvents","#root","#applyTheme","#applyResponsivePaneStyles","#setupResizeObserver","#selectedId","#findTask","#scheduleRender","#input","#patchTask","#assertAlive","#rafPending","#rafId","#render","#rebuildLeftPaneHeader","#rightPane","#renderGrid","#renderTimeline","#buildExpandCollapseAllPayload","#destroyed","#scrollEl","#onScroll","#resizeObserver","#columnResizeCleanup","#rightPaneRefs","#handleGridClick","#lastGridClick","#scrollTop","#userSplitWidth","#leftPane","#computeState","#rightHeader","#renderGridInternal","#leftBody","#leftHeader","#wireHeaderTreeControls"],"sources":["../src/lib/errors.ts","../src/lib/domain/tree.ts","../src/lib/domain/dependencies.ts","../src/lib/locale.ts","../src/lib/domain/dateMath.ts","../src/lib/timeline/scale.ts","../src/lib/timeline/pixelMapper.ts","../src/lib/timeline/layoutEngine.ts","../src/lib/rendering/linkRouter.ts","../src/lib/validation/schemas.ts","../src/lib/vanilla/dom/helpers.ts","../src/lib/vanilla/dom/timeHeader.ts","../src/lib/vanilla/dom/gridColumns.ts","../src/lib/vanilla/dom/leftPane.ts","../src/lib/vanilla/dom/dependencyLayer.ts","../src/lib/vanilla/interaction/drag.ts","../src/lib/vanilla/interaction/linkCreation.ts","../src/lib/vanilla/dom/rightPane.ts","../src/lib/vanilla/utils.ts","../src/lib/vanilla/splitter.ts","../src/lib/vanilla/responsive.ts","../src/lib/vanilla/gantt-chart.ts"],"sourcesContent":["export type GanttErrorCode =\n\t| 'PARENT_REFERENCE'\n\t| 'PARENT_CYCLE'\n\t| 'LINK_REFERENCE'\n\t| 'DEPENDENCY_CYCLE'\n\t| 'MILESTONE_LINK_TYPE'\n\t| 'DUPLICATE_LINK_PAIR'\n\t| 'INSTANCE_DESTROYED';\n\n/**\n * Domain-specific error with a machine-readable {@link GanttErrorCode}.\n */\nexport class GanttError extends Error {\n\tpublic readonly code: GanttErrorCode;\n\n\t/**\n\t * @param code - A machine-readable {@link GanttErrorCode} categorising the error.\n\t * @param message - A human-readable description.\n\t */\n\tpublic constructor(code: GanttErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'GanttError';\n\t\tthis.code = code;\n\t}\n}\n","import {type Task as GenTask, type ZodTaskInferred as Task} from '../validation/schemas.ts';\nimport {GanttError} from '../errors.ts';\n\n/**\n * A task node in the render tree, combining the flat {@link Task} input data\n * with computed hierarchy structure.\n *\n * Produced by {@link buildTaskTree}; consumed by virtualized row rendering\n * and the timeline layout engine.\n */\nexport type TaskNode = GenTask<Record<string, unknown>> & {\n\t/** Array of child task nodes in the tree hierarchy. */\n\tchildren: TaskNode[];\n\t/** 0 = root */\n\tdepth: number;\n};\n\nfunction detectParentCycles(tasks: Task[]): void {\n\tconst adj = new Map<number, number[]>();\n\tfor (const task of tasks) {\n\t\tadj.set(task.id, []);\n\t}\n\tfor (const task of tasks) {\n\t\tif (task.parent !== undefined) {\n\t\t\tconst parents = adj.get(task.parent);\n\t\t\tif (parents !== undefined) {\n\t\t\t\tparents.push(task.id);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst WHITE = 0,\n\t\tGRAY = 1,\n\t\tBLACK = 2;\n\tconst color = new Map<number, 0 | 1 | 2>();\n\tconst parent = new Map<number, number>();\n\n\tfor (const id of adj.keys()) {\n\t\tcolor.set(id, WHITE);\n\t}\n\n\tconst dfs = (u: number): void => {\n\t\tcolor.set(u, GRAY);\n\t\tfor (const v of adj.get(u) ?? []) {\n\t\t\tconst vc = color.get(v) ?? WHITE;\n\t\t\tif (vc === GRAY) {\n\t\t\t\tconst path: number[] = [v, u];\n\t\t\t\tlet cur = u;\n\t\t\t\twhile (cur !== v) {\n\t\t\t\t\tconst p = parent.get(cur);\n\t\t\t\t\tif (p === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tpath.push(p);\n\t\t\t\t\tcur = p;\n\t\t\t\t}\n\t\t\t\tthrow new GanttError('PARENT_CYCLE', `Parent cycle detected: ${[...path].reverse().join(' -> ')}`);\n\t\t\t}\n\t\t\tif (vc === WHITE) {\n\t\t\t\tparent.set(v, u);\n\t\t\t\tdfs(v);\n\t\t\t}\n\t\t}\n\t\tcolor.set(u, BLACK);\n\t};\n\n\tfor (const id of adj.keys()) {\n\t\tif ((color.get(id) ?? WHITE) === WHITE) {\n\t\t\tdfs(id);\n\t\t}\n\t}\n}\n\n/**\n * Builds a typed tree from a flat task array.\n * Order of tasks[] is irrelevant — parents need not precede children.\n *\n * @param tasks - The flat array of tasks to convert into a tree.\n * @returns Root-level {@link TaskNode} instances with populated `children`.\n * @throws {GanttError} When a task references a `parent` id that does not exist,\n * when a parent cycle is detected, or when a `parent` points to a\n * milestone or leaf task.\n */\nexport function buildTaskTree(tasks: Task[]): TaskNode[] {\n\tconst map = new Map<number, TaskNode>();\n\tconst roots: TaskNode[] = [];\n\n\t// Pass 0: validate — no parent may point to a milestone or leaf\n\tfor (const task of tasks) {\n\t\tif (task.parent !== undefined) {\n\t\t\tconst parentTask = tasks.find((t) => t.id === task.parent);\n\t\t\tif (parentTask !== undefined && (parentTask.kind === 'milestone' || parentTask.kind === 'task')) {\n\t\t\t\tthrow new GanttError('PARENT_REFERENCE', `Task id=${task.id} cannot have parent id=${task.parent} of kind '${parentTask.kind}'`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Pass 1: allocate nodes\n\tfor (const task of tasks) {\n\t\tmap.set(task.id, {...task, children: [], depth: 0});\n\t}\n\n\t// Pass 2: detect parent cycles via DFS before wiring edges\n\tdetectParentCycles(tasks);\n\n\t// Pass 3: wire parent→child edges\n\tfor (const task of tasks) {\n\t\tconst node = map.get(task.id);\n\t\tif (node === undefined) {\n\t\t\tcontinue;\n\t\t} // unreachable\n\t\tif (task.parent !== undefined) {\n\t\t\tconst parent = map.get(task.parent);\n\t\t\tif (parent === undefined) {\n\t\t\t\tthrow new GanttError('PARENT_REFERENCE', `Task id=${task.id} references non-existent parent id=${task.parent}`);\n\t\t\t}\n\t\t\tparent.children.push(node);\n\t\t} else {\n\t\t\troots.push(node);\n\t\t}\n\t}\n\n\t// Pass 4: compute depths via DFS from roots\n\t(function setDepths(nodes: TaskNode[], d: number): void {\n\t\tfor (const n of nodes) {\n\t\t\tn.depth = d;\n\t\t\tsetDepths(n.children, d + 1);\n\t\t}\n\t})(roots, 0);\n\n\treturn roots;\n}\n\n/**\n * Flattens a tree into a visible row list.\n * A node's children are included only when its id is in `expandedIds`.\n *\n * @param roots - The root-level {@link TaskNode} instances of the tree.\n * @param expandedIds - Set of task IDs whose children should be rendered.\n * @returns A depth-first flattened array of visible {@link TaskNode} items.\n */\nexport function flattenTree(roots: TaskNode[], expandedIds: ReadonlySet<number>): TaskNode[] {\n\tconst rows: TaskNode[] = [];\n\tfunction walk(node: TaskNode): void {\n\t\trows.push(node);\n\t\tif (node.children.length > 0 && expandedIds.has(node.id)) {\n\t\t\tfor (const child of node.children) {\n\t\t\t\twalk(child);\n\t\t\t}\n\t\t}\n\t}\n\tfor (const root of roots) {\n\t\twalk(root);\n\t}\n\treturn rows;\n}\n\n/**\n * Returns `true` when a node has children in the tree.\n *\n * @param node - The {@link TaskNode} to inspect.\n * @returns `true` if `node.children.length > 0`.\n */\nexport function isParent(node: TaskNode): boolean {\n\treturn node.children.length > 0;\n}\n","import {type ZodLinkInferred as Link, type ZodTaskInferred as Task} from '../validation/schemas.ts';\nimport {GanttError} from '../errors.ts';\n\n/**\n * Detects circular dependencies in the link graph using DFS tri-colour marking.\n *\n * @param tasks - The task list (used to build the vertex set).\n * @param links - The dependency links defining the directed edges.\n * @throws {GanttError} When a cycle is detected, with a human-readable cycle path.\n */\nexport function detectCycles(tasks: Task[], links: Link[]): void {\n\t// Build adjacency list (directed: source → target)\n\tconst adj = new Map<number, number[]>();\n\tfor (const task of tasks) {\n\t\tadj.set(task.id, []);\n\t}\n\tfor (const link of links) {\n\t\tconst neighbors = adj.get(link.source);\n\t\tif (neighbors !== undefined) {\n\t\t\tneighbors.push(link.target);\n\t\t}\n\t}\n\n\tconst WHITE = 0,\n\t\tGRAY = 1,\n\t\tBLACK = 2;\n\tconst color = new Map<number, 0 | 1 | 2>();\n\tconst parent = new Map<number, number>();\n\n\tfor (const id of adj.keys()) {\n\t\tcolor.set(id, WHITE);\n\t}\n\n\tconst dfs = (u: number): void => {\n\t\tcolor.set(u, GRAY);\n\t\tfor (const v of adj.get(u) ?? []) {\n\t\t\tconst vc = color.get(v) ?? WHITE;\n\t\t\tif (vc === GRAY) {\n\t\t\t\t// Back-edge found — reconstruct cycle\n\t\t\t\tconst path: number[] = [v, u];\n\t\t\t\tlet cur = u;\n\t\t\t\twhile (cur !== v) {\n\t\t\t\t\tconst p = parent.get(cur);\n\t\t\t\t\tif (p === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tpath.push(p);\n\t\t\t\t\tcur = p;\n\t\t\t\t}\n\t\t\t\tthrow new GanttError('DEPENDENCY_CYCLE', `Circular dependency detected: ${[...path].reverse().join(' -> ')}`);\n\t\t\t}\n\t\t\tif (vc === WHITE) {\n\t\t\t\tparent.set(v, u);\n\t\t\t\tdfs(v);\n\t\t\t}\n\t\t}\n\t\tcolor.set(u, BLACK);\n\t};\n\n\tfor (const id of adj.keys()) {\n\t\tif ((color.get(id) ?? WHITE) === WHITE) {\n\t\t\tdfs(id);\n\t\t}\n\t}\n}\n\n/**\n * Validates that every link references existing task IDs and that no\n * duplicate (source, target) pairs exist.\n *\n * @param tasks - The task list (used as the reference set of valid IDs).\n * @param links - The dependency links to validate.\n * @throws {GanttError} When any link references a non-existent source or target task,\n * when a non-FS link connects to/from a milestone, or when duplicate\n * (source, target) pairs exist.\n */\nexport function validateLinkRefs(tasks: Task[], links: Link[]): void {\n\tconst ids = new Set(tasks.map((t) => t.id));\n\tconst taskById = new Map(tasks.map((t) => [t.id, t]));\n\tconst pairKeys = new Set<string>();\n\n\tfor (const link of links) {\n\t\tif (!ids.has(link.source)) {\n\t\t\tthrow new GanttError('LINK_REFERENCE', `Link id=${link.id}: source=${link.source} not found`);\n\t\t}\n\t\tif (!ids.has(link.target)) {\n\t\t\tthrow new GanttError('LINK_REFERENCE', `Link id=${link.id}: target=${link.target} not found`);\n\t\t}\n\n\t\tconst pairKey = `${link.source}:${link.target}`;\n\t\tif (pairKeys.has(pairKey)) {\n\t\t\tthrow new GanttError('DUPLICATE_LINK_PAIR', `Link id=${link.id}: duplicate pair source=${link.source} target=${link.target}`);\n\t\t}\n\t\tpairKeys.add(pairKey);\n\n\t\tif (link.type !== 'FS') {\n\t\t\tconst sourceTask = taskById.get(link.source);\n\t\t\tconst targetTask = taskById.get(link.target);\n\t\t\tif (sourceTask?.kind === 'milestone' || targetTask?.kind === 'milestone') {\n\t\t\t\tthrow new GanttError('MILESTONE_LINK_TYPE', `Link id=${link.id}: non-FS type '${link.type}' not allowed when connected to a milestone`);\n\t\t\t}\n\t\t}\n\t}\n}\n","export type LocaleLabelKey =\n\t| 'ariaTask'\n\t| 'ariaMilestone'\n\t| 'addSubtaskTitle'\n\t| 'expandAllTitle'\n\t| 'collapseAllTitle'\n\t| 'columnTaskName'\n\t| 'columnStartDate'\n\t| 'columnEndDate'\n\t| 'columnDuration'\n\t| 'columnQuarter';\n\nexport type ChartLocale = {\n\tcode: string;\n\tlabels?: Partial<Record<LocaleLabelKey, string>>;\n\tweekStartsOn?: 0 | 1 | 6;\n\tweekNumbering?: 'iso' | 'us' | 'simple';\n\tweekendDays?: number[];\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype IntlLocaleWithWeekInfo = Intl.Locale & {getWeekInfo?: () => {firstDay: number; weekend: number[]; minimalDays: number}};\n\nconst WEEK_START_REGION: Record<string, 0 | 1 | 6> = {\n\tUS: 0,\n\tCA: 0,\n\tMX: 0,\n\tJP: 0,\n\tPH: 0,\n\tBR: 0,\n\tCO: 0,\n\tVE: 0,\n\tPE: 0,\n\tEC: 0,\n\tCL: 0,\n\tAR: 0,\n\tUY: 0,\n\tPY: 0,\n\tBO: 0,\n\tGT: 0,\n\tHN: 0,\n\tSV: 0,\n\tNI: 0,\n\tCR: 0,\n\tPA: 0,\n\tDO: 0,\n\tPR: 0,\n\tIL: 0,\n\tSA: 0,\n\tKW: 0,\n\tQA: 0,\n\tBH: 0,\n\tOM: 0,\n\tYE: 0,\n\tMA: 0,\n\tDZ: 0,\n\tTN: 0,\n\tLY: 0,\n\tEG: 0,\n\tIQ: 0,\n\tJO: 0,\n\tSD: 0,\n\tSY: 0,\n\tLB: 0,\n\tPS: 0,\n\tAE: 6,\n\tIR: 6,\n\tAF: 6,\n\tDJ: 6,\n\tSO: 6,\n};\n\nconst WEEK_START_LANG: Record<string, 0 | 1 | 6> = {\n\tar: 6,\n\tfa: 6,\n};\n\nconst WEEK_NUMBERING_REGION: Record<string, 'iso' | 'us'> = {\n\tUS: 'us',\n\tCA: 'us',\n\tMX: 'us',\n\tBR: 'us',\n\tAR: 'us',\n\tCL: 'us',\n\tCO: 'us',\n\tPE: 'us',\n\tJP: 'us',\n\tKR: 'us',\n\tCN: 'us',\n\tTW: 'us',\n\tIN: 'us',\n\tPH: 'us',\n\tIL: 'us',\n\tSA: 'us',\n\tAE: 'us',\n\tIR: 'us',\n\tZA: 'us',\n\tAU: 'us',\n\tNZ: 'us',\n};\n\nconst WEEKEND_REGION: Record<string, number[]> = {\n\tAE: [5, 6],\n\tAF: [4, 5],\n\tDZ: [5, 6],\n\tBH: [5, 6],\n\tBD: [5, 6],\n\tEG: [5, 6],\n\tIQ: [5, 6],\n\tIL: [5, 6],\n\tJO: [5, 6],\n\tKW: [5, 6],\n\tLY: [5, 6],\n\tMV: [5, 6],\n\tMR: [5, 6],\n\tMA: [5, 6],\n\tOM: [5, 6],\n\tPK: [5, 6],\n\tPS: [5, 6],\n\tQA: [5, 6],\n\tSA: [5, 6],\n\tSD: [5, 6],\n\tSY: [5, 6],\n\tTN: [5, 6],\n\tYE: [5, 6],\n\tBN: [5, 0],\n\tIN: [0],\n\tUG: [0],\n\tNP: [6],\n\tIR: [5],\n\tDJ: [4, 5],\n\tSO: [5],\n\tMY: [5, 0],\n};\n\nexport const EN_US_LABELS: Record<LocaleLabelKey, string> = {\n\tariaTask: 'Task {0}',\n\tariaMilestone: 'Milestone {0}',\n\taddSubtaskTitle: 'Add subtask',\n\texpandAllTitle: 'Expand all',\n\tcollapseAllTitle: 'Collapse all',\n\tcolumnTaskName: 'Task name',\n\tcolumnStartDate: 'Start',\n\tcolumnEndDate: 'End',\n\tcolumnDuration: 'Duration',\n\tcolumnQuarter: 'Q',\n};\n\nfunction tryGetWeekInfo(code: string): {firstDay: number; weekend: number[]; minimalDays: number} | undefined {\n\ttry {\n\t\tif (typeof Intl !== 'undefined' && typeof Intl.Locale === 'function') {\n\t\t\tconst locale = new Intl.Locale(code) as IntlLocaleWithWeekInfo;\n\t\t\tconst fn = locale.getWeekInfo;\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\treturn fn.call(locale);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Not available — use fallback mapping table\n\t}\n\treturn undefined;\n}\n\n/**\n * Derives the first day of week (0=Sun, 1=Mon, 6=Sat) from a BCP 47 code.\n * Uses `Intl.Locale.getWeekInfo()` where available (Chromium, Safari 15.4+),\n * with a CLDR-based fallback table for Firefox and older runtimes.\n *\n * @param code - A BCP 47 language tag (e.g. `'en-US'`, `'de-DE'`).\n * @returns The first day of the week: `0` (Sunday), `1` (Monday), or `6` (Saturday).\n */\nexport function deriveWeekStartsOn(code: string): 0 | 1 | 6 {\n\tconst primary = code.split('-')[0]?.toLowerCase() ?? 'en';\n\tconst region = code.split('-')[1]?.toUpperCase();\n\n\tif (region !== undefined) {\n\t\tconst fromRegion = WEEK_START_REGION[region];\n\t\tif (fromRegion !== undefined) {\n\t\t\treturn fromRegion;\n\t\t}\n\t}\n\tconst fromLang = WEEK_START_LANG[primary];\n\tif (fromLang !== undefined) {\n\t\treturn fromLang;\n\t}\n\n\tconst info = tryGetWeekInfo(code);\n\tif (info !== undefined) {\n\t\tconst day = info.firstDay;\n\t\treturn (day === 7 ? 0 : day) as 0 | 1 | 6;\n\t}\n\n\treturn 1;\n}\n\n/**\n * Derives the week numbering scheme from a BCP 47 code.\n * Europe and ISO-aligned regions default to `'iso'`; Americas and others to `'us'`.\n *\n * @param code - A BCP 47 language tag (e.g. `'en-US'`, `'de-DE'`).\n * @returns The week numbering scheme: `'iso'`, `'us'`, or `'simple'`.\n */\nexport function deriveWeekNumbering(code: string): 'iso' | 'us' | 'simple' {\n\tconst region = code.split('-')[1]?.toUpperCase();\n\tif (region !== undefined) {\n\t\tconst fromRegion = WEEK_NUMBERING_REGION[region];\n\t\tif (fromRegion !== undefined) {\n\t\t\treturn fromRegion;\n\t\t}\n\t\tif (region in WEEK_START_REGION) {\n\t\t\treturn 'us';\n\t\t}\n\t}\n\n\tconst info = tryGetWeekInfo(code);\n\tif (info !== undefined) {\n\t\tif (info.minimalDays >= 4 && info.firstDay === 1) {\n\t\t\treturn 'iso';\n\t\t}\n\t\treturn 'us';\n\t}\n\n\treturn 'iso';\n}\n\n/**\n * Derives weekend days (0=Sun … 6=Sat) from a BCP 47 code.\n * Uses `Intl.Locale.getWeekInfo()` where available, with a CLDR-based fallback table.\n *\n * @param code - A BCP 47 language tag (e.g. `'en-US'`, `'de-DE'`).\n * @returns An array of weekend day indices (sorted ascending).\n */\nexport function deriveWeekendDays(code: string): number[] {\n\tconst region = code.split('-')[1]?.toUpperCase();\n\tif (region !== undefined) {\n\t\tconst fromRegion = WEEKEND_REGION[region];\n\t\tif (fromRegion !== undefined) {\n\t\t\tconst days = [...fromRegion];\n\t\t\tdays.sort((a, b) => a - b);\n\t\t\treturn days;\n\t\t}\n\t}\n\n\tconst info = tryGetWeekInfo(code);\n\tif (info !== undefined) {\n\t\tconst days = info.weekend.map((d: number) => (d === 7 ? 0 : d));\n\t\tdays.sort((a, b) => a - b);\n\t\treturn days;\n\t}\n\n\treturn [0, 6];\n}\n\n/**\n * Resolves a {@link ChartLocale} from either a full `ChartLocale` object or a BCP 47 string.\n * When given a string, derives `weekStartsOn`, `weekNumbering`, and `weekendDays` from CLDR conventions.\n *\n * @param raw - A {@link ChartLocale} object, a BCP 47 language tag string, or `undefined`.\n * @returns A fully resolved {@link ChartLocale} with defaults applied.\n */\nexport function resolveChartLocale(raw: ChartLocale | string | undefined): ChartLocale {\n\tif (raw === undefined) {\n\t\treturn {\n\t\t\tcode: 'en',\n\t\t\tlabels: EN_US_LABELS,\n\t\t\tweekStartsOn: 0,\n\t\t\tweekNumbering: 'iso',\n\t\t\tweekendDays: [0, 6],\n\t\t};\n\t}\n\tif (typeof raw !== 'string') {\n\t\tconst locale: ChartLocale = {\n\t\t\tcode: raw.code,\n\t\t\tweekStartsOn: raw.weekStartsOn ?? deriveWeekStartsOn(raw.code),\n\t\t\tweekNumbering: raw.weekNumbering ?? deriveWeekNumbering(raw.code),\n\t\t\tweekendDays: raw.weekendDays ?? deriveWeekendDays(raw.code),\n\t\t};\n\t\tif (raw.labels !== undefined) {\n\t\t\tlocale.labels = raw.labels;\n\t\t}\n\t\treturn locale;\n\t}\n\tconst code = raw;\n\treturn {\n\t\tcode,\n\t\tweekStartsOn: deriveWeekStartsOn(code),\n\t\tweekNumbering: deriveWeekNumbering(code),\n\t\tweekendDays: deriveWeekendDays(code),\n\t};\n}\n\nfunction isoWeek(date: Date): number {\n\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\tconst dayNum = d.getUTCDay() || 7;\n\td.setUTCDate(d.getUTCDate() + 4 - dayNum);\n\tconst yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n\treturn Math.ceil(((d.getTime() - yearStart.getTime()) / 86_400_000 + 1) / 7);\n}\n\nfunction usWeek(date: Date): number {\n\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\tconst yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n\tconst dayOfYear = Math.floor((d.getTime() - yearStart.getTime()) / 86_400_000);\n\tconst jan1Dow = yearStart.getUTCDay();\n\tconst daysToFirstWeekStart = jan1Dow === 0 ? 0 : -jan1Dow;\n\tconst weekStartDayOfYear = daysToFirstWeekStart;\n\tif (dayOfYear < weekStartDayOfYear) {\n\t\treturn 0;\n\t}\n\treturn Math.floor((dayOfYear - weekStartDayOfYear) / 7) + 1;\n}\n\nfunction simpleWeek(date: Date): number {\n\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\tconst yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n\tconst dayOfYear = Math.floor((d.getTime() - yearStart.getTime()) / 86_400_000);\n\treturn Math.ceil((dayOfYear + 1) / 7);\n}\n\n/**\n * Formats a week number according to the specified scheme.\n *\n * - `'iso'`: ISO 8601 (week 1 contains the first Thursday; Monday start).\n * - `'us'`: Week 1 contains January 1; Sunday start.\n * - `'simple'`: `Math.ceil(dayOfYear / 7)`.\n *\n * @param date - The date to compute the week number for.\n * @param scheme - The week numbering scheme: `'iso'`, `'us'`, or `'simple'`.\n * @returns The week number as a positive integer.\n */\nexport function formatWeekNumber(date: Date, scheme: 'iso' | 'us' | 'simple'): number {\n\tswitch (scheme) {\n\t\tcase 'iso': {\n\t\t\treturn isoWeek(date);\n\t\t}\n\t\tcase 'us': {\n\t\t\treturn usWeek(date);\n\t\t}\n\t\tcase 'simple': {\n\t\t\treturn simpleWeek(date);\n\t\t}\n\t}\n}\n\n/**\n * Formats a label template by replacing `{0}` with the given argument.\n *\n * @param template - The template string containing `{0}` as placeholder.\n * @param arg - The value to substitute for `{0}`.\n * @returns The formatted string with the placeholder replaced.\n */\nexport function formatLabel(template: string, arg: string): string {\n\treturn template.replaceAll('{0}', arg);\n}\n","import {type TimeScale} from '../timeline/scale.ts';\nimport {type ChartLocale, EN_US_LABELS, formatWeekNumber} from '../locale.ts';\n\n/**\n * Parses `YYYY-MM-DD` → UTC midnight `Date`.\n *\n * @param dateStr - An ISO-8601 date string in `YYYY-MM-DD` format.\n * @returns A `Date` representing UTC midnight of the given date.\n * @throws {Error} When `dateStr` does not represent a valid date.\n */\nexport function parseDate(dateStr: string): Date {\n\tconst d = new Date(`${dateStr}T00:00:00.000Z`);\n\tif (isNaN(d.getTime())) {\n\t\tthrow new Error(`Invalid date: \"${dateStr}\"`);\n\t}\n\treturn d;\n}\n\n/**\n * Returns `date + n` days using exact millisecond arithmetic.\n *\n * @param date - The base date.\n * @param days - Number of days to add (may be negative).\n * @returns A new `Date` offset by the given number of days.\n */\nexport function addDays(date: Date, days: number): Date {\n\treturn new Date(date.getTime() + days * 86_400_000);\n}\n\n/**\n * Returns `date + n` hours using exact millisecond arithmetic.\n *\n * @param date - The base date.\n * @param hours - Number of hours to add (may be negative).\n * @returns A new `Date` offset by the given number of hours.\n */\nexport function addHours(date: Date, hours: number): Date {\n\treturn new Date(date.getTime() + hours * 3_600_000);\n}\n\n/**\n * Difference in days (float). Positive when `b > a`.\n *\n * @param a - The earlier date.\n * @param b - The later date.\n * @returns The fractional number of days between the two dates.\n */\nexport function diffDays(a: Date, b: Date): number {\n\treturn (b.getTime() - a.getTime()) / 86_400_000;\n}\n\n/**\n * Difference in hours (float). Positive when `b > a`.\n *\n * @param a - The earlier date.\n * @param b - The later date.\n * @returns The fractional number of hours between the two dates.\n */\nexport function diffHours(a: Date, b: Date): number {\n\treturn (b.getTime() - a.getTime()) / 3_600_000;\n}\n\n/**\n * Returns the UTC start-of-day for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of the same calendar date.\n */\nexport function startOfDay(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n}\n\n/**\n * UTC start-of-week. Respects locale's `weekStartsOn` (0=Sun, 1=Mon, 6=Sat).\n *\n * @param date - Any `Date`.\n * @param weekStartsOn - First day of the week (`0`-Sun, `1`-Mon, `6`-Sat). Defaults to `1` (Monday).\n * @returns A new `Date` set to UTC midnight of the first day of the containing week.\n */\nexport function startOfWeek(date: Date, weekStartsOn: 0 | 1 | 6 = 1): Date {\n\tconst d = startOfDay(date);\n\tconst dow = d.getUTCDay();\n\tconst offset = (((dow - weekStartsOn) % 7) + 7) % 7;\n\treturn addDays(d, -offset);\n}\n\n/**\n * Returns the UTC start-of-month for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of the first day of the containing month.\n */\nexport function startOfMonth(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n}\n\n/**\n * Returns the UTC start-of-quarter for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of the first day of the containing quarter.\n */\nexport function startOfQuarter(date: Date): Date {\n\tconst month = date.getUTCMonth();\n\tconst quarterStartMonth = Math.floor(month / 3) * 3;\n\treturn new Date(Date.UTC(date.getUTCFullYear(), quarterStartMonth, 1));\n}\n\n/**\n * Returns the UTC start-of-year for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of January 1 of the containing year.\n */\nexport function startOfYear(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), 0, 1));\n}\n\n/**\n * Returns the UTC start-of-hour for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to the start of the containing UTC hour.\n */\nexport function startOfHour(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()));\n}\n\nfunction resolveQuarterLabel(locale: ChartLocale): string {\n\tif (locale.labels?.columnQuarter !== undefined) {\n\t\treturn locale.labels.columnQuarter;\n\t}\n\treturn EN_US_LABELS.columnQuarter;\n}\n\n/**\n * Formats a `Date` for the time-header label given the active scale.\n *\n * @param date - The date to format.\n * @param scale - The active {@link TimeScale} determining the label granularity.\n * @param locale - The {@link ChartLocale} used for formatting.\n * @returns A human-readable header label string.\n */\nexport function formatHeaderLabel(date: Date, scale: TimeScale, locale: ChartLocale): string {\n\tconst {code, weekNumbering: weekNumScheme = 'iso'} = locale;\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn `${String(date.getUTCHours()).padStart(2, '0')}:00`;\n\t\t}\n\t\tcase 'day': {\n\t\t\tconst day = date.toLocaleDateString(code, {weekday: 'short', timeZone: 'UTC'});\n\t\t\treturn `${date.getUTCDate()} ${day}`;\n\t\t}\n\t\tcase 'week': {\n\t\t\tconst wn = formatWeekNumber(date, weekNumScheme);\n\t\t\treturn `W${wn}`;\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn date.toLocaleDateString(code, {month: 'short', year: 'numeric', timeZone: 'UTC'});\n\t\t}\n\t\tcase 'quarter': {\n\t\t\treturn `${resolveQuarterLabel(locale)}${Math.floor(date.getUTCMonth() / 3) + 1} ${date.getUTCFullYear()}`;\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t}\n}\n\n/**\n * Returns the upper-level (month/year) label for a given scale column.\n * Used in the top header row of the timeline.\n *\n * @param date - The date to format.\n * @param scale - The active {@link TimeScale}. Determines how the upper label is computed.\n * @param locale - The {@link ChartLocale} used for formatting.\n * @returns A human-readable upper-level header label string.\n */\nexport function formatUpperLabel(date: Date, scale: TimeScale, locale: ChartLocale): string {\n\tconst {code} = locale;\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn date.toLocaleDateString(code, {month: 'long', day: 'numeric', year: 'numeric', timeZone: 'UTC'});\n\t\t}\n\t\tcase 'day':\n\t\tcase 'week': {\n\t\t\treturn date.toLocaleDateString(code, {month: 'long', year: 'numeric', timeZone: 'UTC'});\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t\tcase 'quarter': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t}\n}\n\n/**\n * Returns the number of days in an inclusive range from `start` to `end`.\n *\n * @param start - The start date.\n * @param end - The end date.\n * @returns The number of days, inclusive.\n */\nexport function getRangeDays(start: Date, end: Date): number {\n\treturn Math.round(diffDays(start, end)) + 1;\n}\n\n/**\n * Calculates the end date for an inclusive range starting at `start` with a given duration in days.\n *\n * @param start - The start date.\n * @param durationDays - The number of days in the range (must be >= 1).\n * @returns The end date.\n */\nexport function getEndDate(start: Date, durationDays: number): Date {\n\treturn addDays(start, Math.max(0, durationDays - 1));\n}\n\n/**\n * Formats a `YYYY-MM-DD` string for display in the grid.\n *\n * @param dateStr - An ISO-8601 date string in `YYYY-MM-DD` format.\n * @param locale - The {@link ChartLocale} used for locale-aware formatting.\n * @returns A locale-formatted date string.\n */\nexport function formatDisplayDate(dateStr: string, locale: ChartLocale): string {\n\tconst d = parseDate(dateStr);\n\treturn d.toLocaleDateString(locale.code, {year: 'numeric', month: '2-digit', day: '2-digit', timeZone: 'UTC'});\n}\n","export type TimeScale = 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';\n\nexport type ScaleConfig = {\n\t/** Pixel width of one column unit */\n\tcolumnWidth: number;\n\t/** Milliseconds per column unit */\n\tmsPerColumn: number;\n\theaderFormat: TimeScale;\n};\n\nconst H = 3_600_000;\nconst D = 86_400_000;\n\nexport const SCALE_CONFIGS: Record<TimeScale, ScaleConfig> = {\n\thour: {columnWidth: 60, msPerColumn: H, headerFormat: 'hour'},\n\tday: {columnWidth: 72, msPerColumn: D, headerFormat: 'day'},\n\tweek: {columnWidth: 120, msPerColumn: 7 * D, headerFormat: 'week'},\n\tmonth: {columnWidth: 160, msPerColumn: 30 * D, headerFormat: 'month'},\n\tquarter: {columnWidth: 220, msPerColumn: 91 * D, headerFormat: 'quarter'},\n\tyear: {columnWidth: 280, msPerColumn: 365 * D, headerFormat: 'year'},\n};\n\n/**\n * Snaps a date to the column boundary for the provided scale.\n * All operations use UTC semantics.\n * The week boundary respects the optional `weekStartsOn` override (0=Sun, 1=Mon, 6=Sat).\n *\n * @param date - The date to snap.\n * @param scale - The target {@link TimeScale}.\n * @param weekStartsOn - First day of the week (`0`-Sun, `1`-Mon, `6`-Sat). Defaults to `1` (Monday).\n * @returns A new `Date` snapped to the column boundary.\n */\nexport function snapToScaleBoundary(date: Date, scale: TimeScale, weekStartsOn: 0 | 1 | 6 = 1): Date {\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()));\n\t\t}\n\t\tcase 'day': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\t\t}\n\t\tcase 'week': {\n\t\t\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\t\t\tconst dow = d.getUTCDay();\n\t\t\tconst offset = (((dow - weekStartsOn) % 7) + 7) % 7;\n\t\t\td.setUTCDate(d.getUTCDate() - offset);\n\t\t\treturn d;\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n\t\t}\n\t\tcase 'quarter': {\n\t\t\tconst month = date.getUTCMonth();\n\t\t\tconst quarterStartMonth = Math.floor(month / 3) * 3;\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), quarterStartMonth, 1));\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), 0, 1));\n\t\t}\n\t}\n}\n\n/**\n * Returns the next column boundary from a boundary-aligned date.\n * Month/quarter/year use true calendar stepping (not fixed-day approximations).\n *\n * @param date - A boundary-aligned date.\n * @param scale - The target {@link TimeScale}.\n * @returns The next boundary date.\n */\nexport function nextScaleBoundary(date: Date, scale: TimeScale): Date {\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn new Date(date.getTime() + H);\n\t\t}\n\t\tcase 'day': {\n\t\t\treturn new Date(date.getTime() + D);\n\t\t}\n\t\tcase 'week': {\n\t\t\treturn new Date(date.getTime() + 7 * D);\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1));\n\t\t}\n\t\tcase 'quarter': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 3, 1));\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear() + 1, 0, 1));\n\t\t}\n\t}\n}\n\n/**\n * Rounds a date up to the end boundary of the containing scale bucket.\n * If the date is already on a boundary, it is returned unchanged.\n *\n * @param date - The date to round.\n * @param scale - The target {@link TimeScale}.\n * @param weekStartsOn - First day of the week (`0`-Sun, `1`-Mon, `6`-Sat). Defaults to `1` (Monday).\n * @returns A boundary-aligned date at or after the input.\n */\nexport function ceilToScaleBoundary(date: Date, scale: TimeScale, weekStartsOn: 0 | 1 | 6 = 1): Date {\n\tconst start = snapToScaleBoundary(date, scale, weekStartsOn);\n\tif (start.getTime() === date.getTime()) {\n\t\treturn start;\n\t}\n\treturn nextScaleBoundary(start, scale);\n}\n","import {SCALE_CONFIGS} from './scale.ts';\nimport {type TimeScale} from './scale.ts';\n\nexport type PixelMapper = {\n\t/** Date → x pixel offset from viewport start */\n\ttoX: (date: Date) => number;\n\t/** x pixel offset → Date */\n\ttoDate: (x: number) => Date;\n\t/** Days → pixel width */\n\tdurationDaysToWidth: (days: number) => number;\n\t/** Pixel width → days (float) */\n\twidthToDurationDays: (px: number) => number;\n\t/** The origin timestamp used for this mapper */\n\toriginMs: number;\n\t/** Pixel width of one column unit */\n\tcolumnWidth: number;\n};\n\n/**\n * Creates a stateless pixel mapper for the given scale and viewport start.\n * All conversions are O(1) arithmetic — safe to call in tight loops.\n *\n * @param scale - The active {@link TimeScale}.\n * @param viewportStart - The leftmost date visible in the viewport.\n * @returns A {@link PixelMapper} configured for the given viewport.\n */\nexport function createPixelMapper(scale: TimeScale, viewportStart: Date): PixelMapper {\n\tconst {columnWidth, msPerColumn} = SCALE_CONFIGS[scale];\n\tconst originMs = viewportStart.getTime();\n\tconst pxPerMs = columnWidth / msPerColumn;\n\tconst msPerPx = msPerColumn / columnWidth;\n\tconst msPerDay = 86_400_000;\n\n\treturn {\n\t\toriginMs,\n\t\tcolumnWidth,\n\t\ttoX(date: Date): number {\n\t\t\treturn (date.getTime() - originMs) * pxPerMs;\n\t\t},\n\t\ttoDate(x: number): Date {\n\t\t\treturn new Date(originMs + x * msPerPx);\n\t\t},\n\t\tdurationDaysToWidth(days: number): number {\n\t\t\treturn days * msPerDay * pxPerMs;\n\t\t},\n\t\twidthToDurationDays(px: number): number {\n\t\t\treturn (px * msPerPx) / msPerDay;\n\t\t},\n\t};\n}\n","import {type TaskNode} from '../domain/tree.ts';\nimport {type PixelMapper} from './pixelMapper.ts';\nimport {parseDate, addHours, getRangeDays} from '../domain/dateMath.ts';\n\nexport const DENSITY = {\n\trowHeight: 44,\n\tbarHeight: 28,\n\tmilestoneSize: 20,\n} as const;\n\nexport const ROW_HEIGHT = DENSITY.rowHeight;\nexport const BAR_HEIGHT = DENSITY.barHeight;\nexport const BAR_Y_OFFSET = (ROW_HEIGHT - BAR_HEIGHT) / 2;\nexport const MILESTONE_SIZE = DENSITY.milestoneSize;\n/** Half-width of a milestone diamond */\nexport const MILESTONE_HALF = MILESTONE_SIZE / 2;\n\nexport type BarLayout = {\n\ttaskId: number;\n\t/** Left edge x in timeline coordinates */\n\tx: number;\n\t/** Top edge y in content coordinates */\n\ty: number;\n\twidth: number;\n\theight: number;\n\tprogressWidth: number;\n\tkind: 'task' | 'project' | 'milestone';\n\trowIndex: number;\n\t/** Center x; identical to x + width/2 or x for milestones */\n\tcenterX: number;\n\tcenterY: number;\n};\n\n/**\n * Computes pixel-space layout for all visible task rows.\n * Returns a map keyed by task id for O(1) lookup during link routing.\n *\n * @param rows - The flattened, visible {@link TaskNode} rows.\n * @param mapper - The {@link PixelMapper} for coordinate conversion.\n * @returns A `Map` from task ID to its computed {@link BarLayout}.\n */\nexport function computeLayout(rows: TaskNode[], mapper: PixelMapper): Map<number, BarLayout> {\n\tconst result = new Map<number, BarLayout>();\n\n\tfor (let i = 0; i < rows.length; i++) {\n\t\tconst task = rows[i];\n\t\tif (task === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst start = parseDate(task.startDate);\n\t\tconst x = mapper.toX(start);\n\t\tconst y = i * ROW_HEIGHT + BAR_Y_OFFSET;\n\t\tconst centerY = i * ROW_HEIGHT + ROW_HEIGHT / 2;\n\n\t\tif (task.kind === 'milestone') {\n\t\t\tresult.set(task.id, {\n\t\t\t\ttaskId: task.id,\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\twidth: 0,\n\t\t\t\theight: BAR_HEIGHT,\n\t\t\t\tprogressWidth: 0,\n\t\t\t\tkind: 'milestone',\n\t\t\t\trowIndex: i,\n\t\t\t\tcenterX: x,\n\t\t\t\tcenterY,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst end = parseDate(task.endDate);\n\t\tconst days = getRangeDays(start, end);\n\t\tconst width = Math.max(mapper.durationDaysToWidth(days), 4);\n\t\tconst progressWidth = width * Math.min(1, Math.max(0, (task.percentComplete ?? 0) / 100));\n\n\t\tresult.set(task.id, {\n\t\t\ttaskId: task.id,\n\t\t\tx,\n\t\t\ty,\n\t\t\twidth,\n\t\t\theight: BAR_HEIGHT,\n\t\t\tprogressWidth,\n\t\t\tkind: task.kind,\n\t\t\trowIndex: i,\n\t\t\tcenterX: x + width / 2,\n\t\t\tcenterY,\n\t\t});\n\t}\n\n\treturn result;\n}\n\n/**\n * Computes the total pixel height of all rows.\n *\n * @param rowCount - The number of visible rows.\n * @returns The total pixel height (`rowCount * ROW_HEIGHT`).\n */\nexport function totalContentHeight(rowCount: number): number {\n\treturn rowCount * ROW_HEIGHT;\n}\n\n/**\n * Derives viewport bounds from task data with padding.\n *\n * @param tasks - The task nodes to derive bounds from.\n * @param paddingHours - Extra hours added before the earliest start and after the latest end. Defaults to `48`.\n * @returns A tuple `[start, end]` of UTC midnight `Date` instances.\n */\nexport function deriveViewport(tasks: TaskNode[], paddingHours = 48): [Date, Date] {\n\tif (tasks.length === 0) {\n\t\tconst now = new Date();\n\t\treturn [now, addHours(now, 720)];\n\t}\n\n\tlet minMs = Infinity;\n\tlet maxMs = -Infinity;\n\n\tfor (const task of tasks) {\n\t\tconst start = parseDate(task.startDate);\n\t\tif (start.getTime() < minMs) {\n\t\t\tminMs = start.getTime();\n\t\t}\n\t\tif (task.kind !== 'milestone') {\n\t\t\tconst end = parseDate(task.endDate);\n\t\t\tif (end.getTime() > maxMs) {\n\t\t\t\tmaxMs = end.getTime();\n\t\t\t}\n\t\t} else if (start.getTime() > maxMs) {\n\t\t\tmaxMs = start.getTime();\n\t\t}\n\t}\n\n\treturn [addHours(new Date(minMs), -paddingHours), addHours(new Date(maxMs), paddingHours)];\n}\n","import {type ZodLinkInferred as Link, type LinkType} from '../validation/schemas.ts';\nimport {type BarLayout} from '../timeline/layoutEngine.ts';\nimport {MILESTONE_HALF, ROW_HEIGHT} from '../timeline/layoutEngine.ts';\n\nexport type Point = {x: number; y: number};\n\nexport type RoutedLink = {\n\tlinkId: number;\n\tsourceTaskId: number;\n\ttargetTaskId: number;\n\ttype: LinkType;\n\t/** Ordered vertices of the orthogonal polyline (source → target). */\n\tpoints: Point[];\n};\n\n/** px gap before/after bar for routing clearance and arrow approach */\nconst TURN_MARGIN = 24;\n\n/** px vertical offset below the bar row for same-row loop detours */\nconst SAME_ROW_DETOUR = 24;\n\n/** Segments shorter than this (px) are collapsed before stroking */\nconst STUB_THRESHOLD = 2;\n\n/**\n * Removes consecutive points whose Euclidean distance is below {@link STUB_THRESHOLD}.\n * The first point is always kept. This prevents near‑zero‑length segments from\n * appearing as visible stubs near the arrowhead.\n *\n * @param points - The ordered vertex list.\n * @returns A filtered copy, guaranteed to contain at least the first point.\n */\nfunction collapseStubs(points: Point[]): Point[] {\n\tconst out: Point[] = [];\n\tfor (const pt of points) {\n\t\tconst last = out.at(-1);\n\t\tif (last === undefined || Math.hypot(pt.x - last.x, pt.y - last.y) >= STUB_THRESHOLD) {\n\t\t\tout.push(pt);\n\t\t}\n\t}\n\treturn out;\n}\n\n// ─── Anchor point helpers ────────────────────────────────────────────────────────\n\n/**\n * True when the dependency arrow enters the target on its **left** edge (FS, SS).\n * False when the arrow enters on the target's **right** edge (FF, SF).\n *\n * The arrowhead uses SVG `orient=\"auto\"` so it rotates to match the direction\n * of the **last** path segment. Therefore:\n *\n * - Left-entry → last segment must travel **RIGHT** (penultimate.x < tx).\n * - Right-entry → last segment must travel **LEFT** (penultimate.x > tx).\n *\n * @param type - The link type.\n * @returns `true` for FS / SS, `false` for FF / SF.\n */\nfunction isLeftEntry(type: Link['type']): boolean {\n\treturn type === 'FS' || type === 'SS';\n}\n\n/**\n * True when the link exits the source bar on its **right** edge (FS, FF).\n * False when it exits on the **left** edge (SS, SF).\n *\n * The first step after the source anchor should move **away** from the bar,\n * **not** into it. This means:\n *\n * - Exit‑right → first horizontal segment goes RIGHT (+TURN_MARGIN).\n * - Exit‑left → first horizontal segment goes LEFT (-TURN_MARGIN).\n *\n * @param type - The link type.\n * @returns `true` for FS / FF, `false` for SS / SF.\n */\nfunction isExitRight(type: Link['type']): boolean {\n\treturn type === 'FS' || type === 'FF';\n}\n\n/**\n * Computes anchor points for the given link type.\n *\n * | Type | Source anchor (`sx`) | Target anchor (`tx`) |\n * |------|-----------------------------|-------------------------------|\n * | FS | right edge of source | left edge of target |\n * | SS | left edge of source | left edge of target |\n * | FF | right edge of source | right edge of target |\n * | SF | left edge of source | right edge of target |\n *\n * Milestone offsets are applied automatically: ± {@link MILESTONE_HALF} replaces\n * ± width for zero‑width milestones.\n *\n * @param type - The link type determining start/end anchor points.\n * @param src - The source bar layout.\n * @param tgt - The target bar layout.\n * @returns Anchor x coordinates `{sx, tx}`.\n * @throws {Error} if the link type is not handled (exhaustiveness guard).\n */\nfunction getAnchors(type: Link['type'], src: BarLayout, tgt: BarLayout): {sx: number; tx: number} {\n\tconst srcRight = src.kind === 'milestone' ? src.x + MILESTONE_HALF : src.x + src.width;\n\tconst srcLeft = src.kind === 'milestone' ? src.x - MILESTONE_HALF : src.x;\n\tconst tgtRight = tgt.kind === 'milestone' ? tgt.x + MILESTONE_HALF : tgt.x + tgt.width;\n\tconst tgtLeft = tgt.kind === 'milestone' ? tgt.x - MILESTONE_HALF : tgt.x;\n\n\tswitch (type) {\n\t\tcase 'FS': {\n\t\t\treturn {sx: srcRight, tx: tgtLeft};\n\t\t}\n\t\tcase 'SS': {\n\t\t\treturn {sx: srcLeft, tx: tgtLeft};\n\t\t}\n\t\tcase 'FF': {\n\t\t\treturn {sx: srcRight, tx: tgtRight};\n\t\t}\n\t\tcase 'SF': {\n\t\t\treturn {sx: srcLeft, tx: tgtRight};\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = type;\n\t\t\tthrow new Error(`Unhandled link type: ${String(_exhaustive)}`);\n\t\t}\n\t}\n}\n\n// ─── Same-row routing ────────────────────────────────────────────────────────────\n\n/**\n * Routes a link whose source and target rows are within 1 px of each other.\n *\n * **Direct‑line optimisation**\n * A plain horizontal segment is only used when it is non‑degenerate (`sx ≠ tx`)\n * AND the arrowhead direction is visually correct:\n *\n * | Entry side | Condition | Arrow direction |\n * |-----------|-----------|----------------|\n * | left | `sx < tx` | → RIGHT ✓ |\n * | right | `sx > tx` | ← LEFT ✓ |\n *\n * Otherwise a 6‑vertex detour is drawn so that the last segment approaches\n * the target from the correct side. By default the detour goes **below** the\n * bars; pass `above = true` when headroom is insufficient below.\n *\n * @param sx - Source anchor x.\n * @param sy - Source row center y.\n * @param tx - Target anchor x.\n * @param ty - Target row center y.\n * @param leftEntry - Whether the link enters the target on its left edge.\n * @param exitRight - Whether the link exits the source on its right edge.\n * @param above - Route the detour above the bar row instead of below (default `false`).\n * @returns An ordered array of {@link Point} vertices.\n */\nfunction routeSameRow(sx: number, sy: number, tx: number, ty: number, leftEntry: boolean, exitRight: boolean, above = false): Point[] {\n\t// Direct horizontal line when non‑degenerate and arrow direction is correct\n\tif (Math.abs(sx - tx) >= STUB_THRESHOLD) {\n\t\tconst directOk = (leftEntry && sx < tx) || (!leftEntry && sx > tx);\n\t\tif (directOk) {\n\t\t\treturn [\n\t\t\t\t{x: sx, y: sy},\n\t\t\t\t{x: tx, y: ty},\n\t\t\t];\n\t\t}\n\t}\n\n\t// ── Loop detour ──\n\t//\n\t// The path steps away from the source edge, drops to the detour level,\n\t// crosses horizontally to an approach point on the correct side of the\n\t// target, then returns to the target entry point.\n\t//\n\t// left‑entry approach right‑entry approach\n\t// ────────────────── ────────────────────\n\t// anchor sx → tx sx → tx\n\t// exit +dir exit +dir\n\t// │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │\n\t// ▼ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │\n\t// ┌──┐│ │ │ │ │ │ │ ┌──┐│ │ │ │ │ │ │\n\t// │ ││ │ │ │ │ │ │ │ ││ │ │ │ │ │ │ (bar row)\n\t// │▐▌││ │ │ │ │ │ │ │▐▌││ │ │ │ │ │ │\n\t// └──┘│ │ │ │ │ │ │ └──┘│ │ │ │ │ │ │\n\t// │ │ │ │ │ │ │ │ │ │ │ │ │ │\n\t// detour ══╪═╪═╪═╪══════► ════════════╪═╪═╪═►\n\t// │ │ │ │ │ │ │ │ │ │ │ │ │ │\n\t// │ │ │ │ │ ▼ ► │ │ │ │ │ │ ▼\n\t// │ │ │ │ └──┐│ │ │ │ │ │ └──┐\n\t// │ │ │ │ │▐▌│ │ │ │ │ │ │▐▌│ (target)\n\t// │ │ │ │ └──┘│ │ │ │ │ │ └──┘\n\t//\n\t// points 6 6\n\t// approach tx - TURN_MARGIN tx + TURN_MARGIN\n\t// last seg → RIGHT → LEFT\n\n\tconst exitDir = exitRight ? TURN_MARGIN : -TURN_MARGIN;\n\tconst detourY = sy + (above ? -SAME_ROW_DETOUR : SAME_ROW_DETOUR);\n\tconst approachX = leftEntry ? tx - TURN_MARGIN : tx + TURN_MARGIN;\n\n\treturn [\n\t\t{x: sx, y: sy},\n\t\t{x: sx + exitDir, y: sy},\n\t\t{x: sx + exitDir, y: detourY},\n\t\t{x: approachX, y: detourY},\n\t\t{x: approachX, y: ty},\n\t\t{x: tx, y: ty},\n\t];\n}\n\n// ─── Multi-row routing ───────────────────────────────────────────────────────────\n\n/**\n * Routes a link between **different** rows using an orthogonal path.\n *\n * 1. Step **away** from the source bar to the crossover x (`crossX`).\n * 2. Travel **vertically** to the midpoint between rows (`midY`).\n * 3. Travel **horizontally** to the approach point on the correct side\n * of the target.\n * 4. Travel **vertically** to the target row (`ty`).\n * 5. Final segment to the target entry point (`tx`).\n *\n * The crossover x is clamped so the path never doubles back past both bars.\n * When exit and entry are on the **same** side (SS / FF) the exit-side step\n * is limited to the approach x, avoiding a wide U‑shape.\n *\n * The approach point is chosen so the last segment travels in the arrow\n * direction demanded by the entry side:\n *\n * - Left‑entry (FS, SS): approach from the **left** → `tx - TURN_MARGIN`\n * Last segment goes RIGHT.\n * - Right‑entry (FF, SF): approach from the **right** → `tx + TURN_MARGIN`\n * Last segment goes LEFT.\n *\n * left‑entry (FS / SS) right‑entry (FF / SF)\n * ───────────────────── ─────────────────────\n * sx ●────────────────► sx ●────────────────►\n * exitDir exitDir\n * │ │\n * │ midY │ midY\n * ▼ ════════════════════► ▼ ════════════════════►\n * │ │\n * │ │\n * ▼ approachFromLeft ▼ approachFromRight\n * ●────────────────► ◄────────────────●\n * tx tx\n *\n * @param sx - Source anchor x.\n * @param sy - Source row center y.\n * @param tx - Target anchor x.\n * @param ty - Target row center y.\n * @param leftEntry - Whether the link enters the target on its left edge.\n * @param exitRight - Whether the link exits the source on its right edge.\n * @returns An ordered array of {@link Point} vertices.\n */\nfunction routeMultiRow(sx: number, sy: number, tx: number, ty: number, leftEntry: boolean, exitRight: boolean): Point[] {\n\tconst rowsApart = Math.round(Math.abs(sy - ty) / ROW_HEIGHT);\n\tconst midY = rowsApart % 2 === 0 ? (sy + ty) / 2 + ROW_HEIGHT / 2 : (sy + ty) / 2;\n\tconst approachX = leftEntry ? tx - TURN_MARGIN : tx + TURN_MARGIN;\n\tconst crossX = exitRight ? Math.max(sx + TURN_MARGIN, approachX) : Math.min(sx - TURN_MARGIN, approachX);\n\n\treturn [\n\t\t{x: sx, y: sy},\n\t\t{x: crossX, y: sy},\n\t\t{x: crossX, y: midY},\n\t\t{x: approachX, y: midY},\n\t\t{x: approachX, y: ty},\n\t\t{x: tx, y: ty},\n\t];\n}\n\n// ─── Entry point ─────────────────────────────────────────────────────────────────\n\n/**\n * Produces the vertex list for an orthogonal connector between source and target.\n *\n * ## Anchor points (sx / tx)\n *\n * | Type | Source anchor (`sx`) | Target anchor (`tx`) |\n * |------|-----------------------------|-------------------------------|\n * | FS | right edge of source | left edge of target |\n * | SS | left edge of source | left edge of target |\n * | FF | right edge of source | right edge of target |\n * | SF | left edge of source | right edge of target |\n *\n * Milestone offsets are applied automatically: ± {@link MILESTONE_HALF} replaces\n * ± width for zero‑width milestones.\n *\n * ## Routing strategy\n *\n * **Same row** (|sy − ty| < 1 px):\n * - Direct horizontal line when non‑degenerate **and** the arrow direction\n * naturally points **into** the target (see {@link routeSameRow}).\n * - Otherwise a 6‑vertex detour below the bars is drawn.\n *\n * **Different rows**: always a 6‑vertex orthogonal path that steps away from\n * the source, passes through the midpoint between rows, and approaches the\n * target from the correct side (see {@link routeMultiRow}).\n *\n * ## Arrowhead direction guarantee\n *\n * The SVG `marker-end` uses `orient=\"auto\"`, so the arrow rotates to match\n * the last segment. This function ensures the last segment always travels\n * **into** the target on the semantically correct edge:\n *\n * | Entry side | Target edge | Last segment direction |\n * |-----------|-------------|-----------------------|\n * | left | left edge | → RIGHT |\n * | right | right edge | ← LEFT |\n *\n * @param type - The link type determining start/end anchor points.\n * @param src - The source bar layout.\n * @param tgt - The target bar layout.\n * @returns An ordered array of {@link Point} vertices.\n */\nfunction route(type: Link['type'], src: BarLayout, tgt: BarLayout): Point[] {\n\tconst {sx, tx} = getAnchors(type, src, tgt);\n\tconst sy = src.centerY;\n\tconst ty = tgt.centerY;\n\n\tconst leftEntry = isLeftEntry(type);\n\tconst exitRight = isExitRight(type);\n\n\tconst raw = Math.abs(sy - ty) < 1 ? routeSameRow(sx, sy, tx, ty, leftEntry, exitRight) : routeMultiRow(sx, sy, tx, ty, leftEntry, exitRight);\n\n\treturn collapseStubs(raw);\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────────\n\n/**\n * Computes orthogonal routing for all dependency links.\n * Links whose source or target is not in the layout map are skipped silently\n * (e.g. when the row is collapsed).\n *\n * @param links - The dependency links to route.\n * @param layouts - A map from task ID to its computed {@link BarLayout}.\n * @returns An array of {@link RoutedLink} objects with computed vertex paths.\n */\nexport function routeLinks(links: Link[], layouts: Map<number, BarLayout>): RoutedLink[] {\n\treturn links\n\t\t.map((link) => {\n\t\t\tconst src = layouts.get(link.source);\n\t\t\tconst tgt = layouts.get(link.target);\n\t\t\tif (src === undefined || tgt === undefined) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlinkId: link.id,\n\t\t\t\tsourceTaskId: link.source,\n\t\t\t\ttargetTaskId: link.target,\n\t\t\t\ttype: link.type,\n\t\t\t\tpoints: route(link.type, src, tgt),\n\t\t\t};\n\t\t})\n\t\t.filter((r): r is RoutedLink => r !== null);\n}\n","import {z} from 'zod';\n\nexport const LinkTypeSchema = z.enum(['FS', 'SS', 'FF', 'SF']);\nexport const TaskKindSchema = z.enum(['task', 'project', 'milestone']);\nconst SpecialDayKindSchema = z.enum(['holiday', 'custom']);\n\n/** @internal */\nexport const SpecialDaySchema = z.object({\n\t/** ISO date: YYYY-MM-DD */\n\tdate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\tkind: SpecialDayKindSchema,\n\tlabel: z.string().min(1).optional(),\n\tclassName: z.string().min(1).optional(),\n});\n\nconst taskBase = {\n\t/** Unique positive integer identifier for the task. */\n\tid: z.number().int().positive(),\n\t/** Display name / label of the task. */\n\ttext: z.string().min(1),\n\t/** ISO date: YYYY-MM-DD */\n\tstartDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\t/** Optional id of the parent task. When set, this task is a child in the hierarchy. */\n\tparent: z.number().int().positive().optional(),\n\t/** Optional CSS color value for the task bar. Overrides the default color assignment. */\n\tcolor: z.string().optional(),\n\t/** When `true`, the task bar cannot be dragged or resized. */\n\treadonly: z.boolean().optional(),\n\t/** Optional arbitrary metadata for consumer use. Preserved in the parsed output. */\n\tdata: z.record(z.string(), z.unknown()).optional(),\n};\n\n/** @internal */\nconst TaskLeafSchema = z\n\t.object({\n\t\t...taskBase,\n\t\tkind: z.literal('task'),\n\t\t/** ISO date: YYYY-MM-DD */\n\t\tendDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\t\t/** 0–100 completion percentage (integer). */\n\t\tpercentComplete: z.number().int().min(0).max(100).default(0),\n\t})\n\t.refine((t) => t.endDate >= t.startDate, {message: 'endDate must be on or after startDate', path: ['endDate']});\n\n/** @internal */\nconst TaskProjectSchema = z\n\t.object({\n\t\t...taskBase,\n\t\tkind: z.literal('project'),\n\t\t/** ISO date: YYYY-MM-DD */\n\t\tendDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\t\t/** 0–100 completion percentage (integer). */\n\t\tpercentComplete: z.number().int().min(0).max(100).default(0),\n\t\t/**\n\t\t * Initial expanded state for tree hierarchy.\n\t\t * When `false`, children of this task are hidden on initial render.\n\t\t *\n\t\t * @default true\n\t\t */\n\t\topen: z.boolean().default(true),\n\t})\n\t.refine((t) => t.endDate >= t.startDate, {message: 'endDate must be on or after startDate', path: ['endDate']});\n\n/** @internal */\nconst TaskMilestoneSchema = z.object({\n\t...taskBase,\n\tkind: z.literal('milestone'),\n});\n\nconst TaskSchema = z.discriminatedUnion('kind', [TaskLeafSchema, TaskProjectSchema, TaskMilestoneSchema]);\n\nconst LinkSchema = z\n\t.object({\n\t\t/** Unique positive integer identifier for the dependency link. */\n\t\tid: z.number().int().positive(),\n\t\t/** The `id` of the predecessor task (the task that drives the dependency). */\n\t\tsource: z.number().int().positive(),\n\t\t/** The `id` of the successor task (the task that depends on the predecessor). */\n\t\ttarget: z.number().int().positive(),\n\t\t/**\n\t\t * Dependency type.\n\t\t *\n\t\t * - `'FS'` — Finish-to-start: successor starts after predecessor finishes.\n\t\t * - `'SS'` — Start-to-start: successor starts at the same time as predecessor.\n\t\t * - `'FF'` — Finish-to-finish: successor finishes at the same time as predecessor.\n\t\t * - `'SF'` — Start-to-finish: successor finishes after predecessor starts.\n\t\t *\n\t\t * @default 'FS'\n\t\t */\n\t\ttype: LinkTypeSchema.default('FS'),\n\t\t/** When `true`, the link cannot be modified or deleted through the UI. */\n\t\treadonly: z.boolean().optional(),\n\t\t/** Optional arbitrary metadata for consumer use. Preserved in the parsed output. */\n\t\tdata: z.record(z.string(), z.unknown()).optional(),\n\t})\n\t.refine((l) => l.source !== l.target, {\n\t\tmessage: 'A link cannot connect a task to itself',\n\t\tpath: ['target'],\n\t});\n\n/** @internal */\nexport const GanttInputSchema = z\n\t.object({\n\t\t/** Array of task objects. At least one task is required. */\n\t\ttasks: z.array(TaskSchema).min(1),\n\t\t/** Optional array of dependency link objects. Defaults to empty array. */\n\t\tlinks: z.array(LinkSchema).default([]),\n\t})\n\t.superRefine((data, ctx) => {\n\t\t// Duplicate task IDs\n\t\tconst taskIds = new Set<number>();\n\t\tfor (let i = 0; i < data.tasks.length; i++) {\n\t\t\tconst task = data.tasks[i];\n\t\t\tif (task !== undefined) {\n\t\t\t\tif (taskIds.has(task.id)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Duplicate task id: ${task.id}`,\n\t\t\t\t\t\tpath: ['tasks', i, 'id'],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\ttaskIds.add(task.id);\n\t\t\t}\n\t\t}\n\n\t\t// Duplicate link IDs\n\t\tconst linkIds = new Set<number>();\n\t\tfor (let i = 0; i < data.links.length; i++) {\n\t\t\tconst link = data.links[i];\n\t\t\tif (link !== undefined) {\n\t\t\t\tif (linkIds.has(link.id)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Duplicate link id: ${link.id}`,\n\t\t\t\t\t\tpath: ['links', i, 'id'],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tlinkIds.add(link.id);\n\t\t\t}\n\t\t}\n\n\t\t// Duplicate (source, target) pairs\n\t\tconst pairKeys = new Set<string>();\n\t\tfor (let i = 0; i < data.links.length; i++) {\n\t\t\tconst link = data.links[i];\n\t\t\tif (link !== undefined) {\n\t\t\t\tconst key = `${link.source}:${link.target}`;\n\t\t\t\tif (pairKeys.has(key)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Duplicate link pair: source=${link.source} target=${link.target}`,\n\t\t\t\t\t\tpath: ['links', i],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tpairKeys.add(key);\n\t\t\t}\n\t\t}\n\t});\n\n// ─── Internal zod-inferred types (runtime shapes, include data?: Record<string, unknown>) ───\n\n/** @internal */\nexport type ZodTaskInferred = z.infer<typeof TaskSchema>;\n/** @internal */\nexport type ZodLinkInferred = z.infer<typeof LinkSchema>;\n\n// ─── Public generic types ───\n\n/**\n * A task in the Gantt chart — discriminated by `kind` into leaf tasks,\n * summary projects, and milestones.\n *\n * @param TData - The type of the optional `data` property. Defaults to `never`,\n * which omits the `data` property from the type. Specify a concrete type to enable\n * compile-time-checked task data in both input and callback payloads.\n *\n * @example\n * ```ts\n * // Default: no `data` property\n * const task: Task = { id: 1, text: 'Build', startDate: '2026-01-01', endDate: '2026-01-03', kind: 'task' };\n *\n * // With typed data\n * interface TaskMeta { priority: number; label: string }\n * const typedTask: Task<TaskMeta> = {\n * id: 1, text: 'Build', startDate: '2026-01-01', endDate: '2026-01-03',\n * kind: 'task', data: { priority: 1, label: 'critical' }\n * };\n * ```\n */\nexport type Task<TData = never> =\n\t| {\n\t\t\tid: number;\n\t\t\ttext: string;\n\t\t\tstartDate: string;\n\t\t\tparent?: number | undefined;\n\t\t\tcolor?: string | undefined;\n\t\t\treadonly?: boolean | undefined;\n\t\t\tdata?: unknown;\n\t\t\tkind: 'task';\n\t\t\tendDate: string;\n\t\t\tpercentComplete: number;\n\t }\n\t| {\n\t\t\tid: number;\n\t\t\ttext: string;\n\t\t\tstartDate: string;\n\t\t\tparent?: number | undefined;\n\t\t\tcolor?: string | undefined;\n\t\t\treadonly?: boolean | undefined;\n\t\t\tdata?: unknown;\n\t\t\tkind: 'project';\n\t\t\tendDate: string;\n\t\t\tpercentComplete: number;\n\t\t\topen: boolean;\n\t }\n\t| {\n\t\t\tid: number;\n\t\t\ttext: string;\n\t\t\tstartDate: string;\n\t\t\tparent?: number | undefined;\n\t\t\tcolor?: string | undefined;\n\t\t\treadonly?: boolean | undefined;\n\t\t\tdata?: unknown;\n\t\t\tkind: 'milestone';\n\t } extends infer _U\n\t? _U extends unknown\n\t\t? Omit<_U, 'data'> &\n\t\t\t\t([TData] extends [never]\n\t\t\t\t\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\t\t\t\t\tRecord<never, never>\n\t\t\t\t\t: {data?: TData | undefined})\n\t\t: never\n\t: never;\n\n/**\n * A dependency link between two tasks.\n *\n * @param TData - The type of the optional `data` property. Defaults to `never`.\n */\nexport type Link<TData = never> = {\n\tid: number;\n\tsource: number;\n\ttarget: number;\n\ttype: LinkType;\n\treadonly?: boolean | undefined;\n} & ([TData] extends [never]\n\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\tRecord<never, never>\n\t: {data?: TData | undefined});\n\n/**\n * The complete input data for the chart.\n *\n * @param TTaskData - The type of the `data` property on tasks. Defaults to `never`.\n * @param TLinkData - The type of the `data` property on links. Defaults to `never`.\n */\nexport type GanttInput<TTaskData = never, TLinkData = never> = {\n\ttasks: Task<TTaskData>[];\n\tlinks: Link<TLinkData>[];\n};\n\n/** @internal */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type _GanttInputZod = z.infer<typeof GanttInputSchema>;\n\n/**\n * The raw input shape that consumers pass to {@link GanttChart.update}.\n *\n * Fields with defaults in the schema (e.g. `percentComplete`, `type`) remain optional here.\n *\n * @param TTaskData - The type of the `data` property on tasks. Defaults to `never`.\n * @param TLinkData - The type of the `data` property on links. Defaults to `never`.\n */\nexport type GanttInputRaw<TTaskData = never, TLinkData = never> = {\n\ttasks: readonly (\n\t\t| {\n\t\t\t\tid: number;\n\t\t\t\ttext: string;\n\t\t\t\tstartDate: string;\n\t\t\t\tparent?: number | undefined;\n\t\t\t\tcolor?: string | undefined;\n\t\t\t\treadonly?: boolean | undefined;\n\t\t\t\tdata?: unknown;\n\t\t\t\tkind: 'task';\n\t\t\t\tendDate: string;\n\t\t\t\tpercentComplete?: number | undefined;\n\t\t }\n\t\t| {\n\t\t\t\tid: number;\n\t\t\t\ttext: string;\n\t\t\t\tstartDate: string;\n\t\t\t\tparent?: number | undefined;\n\t\t\t\tcolor?: string | undefined;\n\t\t\t\treadonly?: boolean | undefined;\n\t\t\t\tdata?: unknown;\n\t\t\t\tkind: 'project';\n\t\t\t\tendDate: string;\n\t\t\t\tpercentComplete?: number | undefined;\n\t\t\t\topen?: boolean | undefined;\n\t\t }\n\t\t| {\n\t\t\t\tid: number;\n\t\t\t\ttext: string;\n\t\t\t\tstartDate: string;\n\t\t\t\tparent?: number | undefined;\n\t\t\t\tcolor?: string | undefined;\n\t\t\t\treadonly?: boolean | undefined;\n\t\t\t\tdata?: unknown;\n\t\t\t\tkind: 'milestone';\n\t\t } extends infer _RU\n\t\t? _RU extends unknown\n\t\t\t? Omit<_RU, 'data'> &\n\t\t\t\t\t([TTaskData] extends [never]\n\t\t\t\t\t\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\t\t\t\t\t\tRecord<never, never>\n\t\t\t\t\t\t: {data?: TTaskData | undefined})\n\t\t\t: never\n\t\t: never)[];\n\tlinks?: readonly ({\n\t\tid: number;\n\t\tsource: number;\n\t\ttarget: number;\n\t\ttype?: LinkType | undefined;\n\t\treadonly?: boolean | undefined;\n\t} & ([TLinkData] extends [never]\n\t\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\t\tRecord<never, never>\n\t\t: {data?: TLinkData | undefined}))[];\n};\n/** Allowed dependency link type values: `'FS'`, `'SS'`, `'FF'`, or `'SF'`. */\nexport type LinkType = 'FS' | 'SS' | 'FF' | 'SF';\n/** Allowed task kind values: `'task'`, `'project'`, or `'milestone'`. */\nexport type TaskKind = 'task' | 'project' | 'milestone';\nexport type SpecialDayKind = 'holiday' | 'custom';\nexport type SpecialDay = {\n\t/** ISO date: YYYY-MM-DD */\n\tdate: string;\n\tkind: SpecialDayKind;\n\tlabel?: string | undefined;\n\tclassName?: string | undefined;\n};\n/** @internal */\nexport type TaskLeafInferred = z.infer<typeof TaskLeafSchema>;\n/** @internal */\nexport type TaskProjectInferred = z.infer<typeof TaskProjectSchema>;\n/** @internal */\nexport type TaskMilestoneInferred = z.infer<typeof TaskMilestoneSchema>;\n","/**\n * Batches style assignments; avoids repeated style recalculations.\n *\n * @param elem - The target element.\n * @param styles - A partial CSS style declaration to apply.\n */\nexport function css(elem: HTMLElement, styles: Partial<CSSStyleDeclaration>): void {\n\tfor (const [k, v] of Object.entries(styles)) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t(elem.style as any)[k] = v ?? '';\n\t}\n}\n\n/**\n * Typed element factory. Avoids littering `as HTMLElement` casts everywhere.\n *\n * @example\n * const div = el('div', {className: 'gantt-bar'});\n * const svg = el('svg', {}, 'http://www.w3.org/2000/svg');\n */\nexport function el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Partial<HTMLElementTagNameMap[K]>, ns?: never): HTMLElementTagNameMap[K];\nexport function el(tag: string, props?: Record<string, unknown>, ns?: string): Element;\nexport function el(tag: string, props?: Record<string, unknown>, ns?: string): Element {\n\tconst elem = ns ? document.createElementNS(ns, tag) : document.createElement(tag);\n\tif (props !== undefined) {\n\t\tfor (const [k, v] of Object.entries(props)) {\n\t\t\tif (k === 'style' && typeof v === 'object' && v !== null) {\n\t\t\t\tcss(elem as HTMLElement, v as Partial<CSSStyleDeclaration>);\n\t\t\t} else if (k in elem) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t(elem as any)[k] = v;\n\t\t\t} else {\n\t\t\t\telem.setAttribute(k, String(v));\n\t\t\t}\n\t\t}\n\t}\n\treturn elem;\n}\n\n/**\n * Removes all child nodes from elem. Faster than `innerHTML = ''` for large subtrees.\n *\n * @param elem - The element to clear.\n */\nexport function clearChildren(elem: Element): void {\n\twhile (elem.firstChild !== null) {\n\t\telem.removeChild(elem.firstChild);\n\t}\n}\n\n/**\n * Appends all nodes from an array/fragment into parent in one pass.\n *\n * @param parent - The parent element.\n * @param children - The child elements or text nodes to append.\n */\nexport function appendAll(parent: Element, children: (Element | Text)[]): void {\n\tconst frag = document.createDocumentFragment();\n\tfor (const c of children) {\n\t\tfrag.appendChild(c);\n\t}\n\tparent.append(frag);\n}\n\n/**\n * Creates an SVG element in the SVG namespace.\n *\n * @param tag - The SVG tag name.\n * @param attrs - Optional attributes to set on the element.\n * @returns A new SVG element.\n */\nexport function svgEl<K extends keyof SVGElementTagNameMap>(tag: K, attrs?: Record<string, string | number>): SVGElementTagNameMap[K] {\n\tconst NS = 'http://www.w3.org/2000/svg';\n\tconst elem = document.createElementNS(NS, tag);\n\tif (attrs !== undefined) {\n\t\tfor (const [k, v] of Object.entries(attrs)) {\n\t\t\telem.setAttribute(k, String(v));\n\t\t}\n\t}\n\treturn elem;\n}\n\n/**\n * Sets multiple SVG attributes in one call.\n *\n * @param elem - The target SVG element.\n * @param attrs - Attributes to set (values are stringified).\n */\nexport function setAttrs(elem: Element, attrs: Record<string, string | number>): void {\n\tfor (const [k, v] of Object.entries(attrs)) {\n\t\telem.setAttribute(k, String(v));\n\t}\n}\n","import {el, clearChildren, appendAll} from './helpers.ts';\nimport {type GanttState, type ResolvedSpecialDay} from '../state.ts';\nimport {nextScaleBoundary, snapToScaleBoundary} from '../../timeline/scale.ts';\nimport {formatHeaderLabel, formatUpperLabel, startOfDay} from '../../domain/dateMath.ts';\n\ntype Cell = {label: string; x: number; width: number};\n\nfunction specialDayKind(\n\tdate: Date,\n\tspecialDaysByDate: Map<string, ResolvedSpecialDay>,\n\tshowWeekends: boolean,\n\tweekendDays: Set<number>,\n): 'weekend' | 'holiday' | 'custom' | null {\n\tconst dateKey = startOfDay(date).toISOString().slice(0, 10);\n\tconst specialDay = specialDaysByDate.get(dateKey);\n\tif (specialDay !== undefined) {\n\t\treturn specialDay.kind;\n\t}\n\tif (showWeekends && weekendDays.has(date.getUTCDay())) {\n\t\treturn 'weekend';\n\t}\n\treturn null;\n}\n\n/**\n * Inline style helper local to this module.\n *\n * @param elem - The target element.\n * @param styles - A partial CSS style declaration to apply.\n */\nfunction css_(elem: HTMLElement, styles: Partial<CSSStyleDeclaration>): void {\n\tfor (const [k, v] of Object.entries(styles)) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t(elem.style as any)[k] = v ?? '';\n\t}\n}\n\n/**\n * Fully replaces the content of `container` with two header rows.\n * Called on scale change or viewport change only — not on scroll.\n *\n * @param container - The header container element to render into.\n * @param state - The current chart state.\n */\nexport function renderTimeHeader(container: HTMLElement, state: GanttState): void {\n\tconst {scale, viewportStart, viewportEnd, mapper, totalWidth, locale, showWeekends, weekendDays, specialDaysByDate} = state;\n\tconst weekStartsOn = locale.weekStartsOn ?? 1;\n\n\tconst upperCells: Cell[] = [];\n\tconst lowerCells: {label: string; x: number; width: number; date: Date}[] = [];\n\n\tlet cur = snapToScaleBoundary(viewportStart, scale, weekStartsOn);\n\tlet prevUpperLabel = '';\n\tlet upperStart = 0;\n\tlet upperWidth = 0;\n\n\twhile (cur < viewportEnd) {\n\t\tconst next = nextScaleBoundary(cur, scale);\n\t\tconst x = mapper.toX(cur);\n\t\tconst w = mapper.toX(next) - x;\n\t\tlowerCells.push({label: formatHeaderLabel(cur, scale, locale), x, width: w, date: new Date(cur)});\n\n\t\tconst uLabel = formatUpperLabel(cur, scale, locale);\n\t\tif (uLabel !== prevUpperLabel) {\n\t\t\tif (prevUpperLabel !== '') {\n\t\t\t\tupperCells.push({label: prevUpperLabel, x: upperStart, width: upperWidth});\n\t\t\t}\n\t\t\tprevUpperLabel = uLabel;\n\t\t\tupperStart = x;\n\t\t\tupperWidth = w;\n\t\t} else {\n\t\t\tupperWidth += w;\n\t\t}\n\t\tcur = next;\n\t}\n\tif (prevUpperLabel !== '') {\n\t\tupperCells.push({label: prevUpperLabel, x: upperStart, width: upperWidth});\n\t}\n\n\t// ── Upper row ──────────────────────────────────────────────────────────\n\tconst upperRow = el('div');\n\tcss_(upperRow, {\n\t\tposition: 'relative',\n\t\theight: '24px',\n\t\twidth: `${totalWidth}px`,\n\t\tbackground: 'var(--gantt-header-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t});\n\n\tconst upperNodes = upperCells.map((cell) => {\n\t\tconst d = el('div');\n\t\tcss_(d, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${cell.x}px`,\n\t\t\twidth: `${cell.width}px`,\n\t\t\theight: '100%',\n\t\t\tborderRight: '1px solid var(--gantt-border)',\n\t\t\tdisplay: 'flex',\n\t\t\talignItems: 'center',\n\t\t\tpaddingLeft: '8px',\n\t\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\tcolor: 'var(--gantt-text)',\n\t\t\toverflow: 'hidden',\n\t\t\twhiteSpace: 'nowrap',\n\t\t\tletterSpacing: 'var(--gantt-letter-spacing-tight)',\n\t\t\ttextTransform: 'uppercase',\n\t\t});\n\t\td.textContent = cell.label;\n\t\treturn d;\n\t});\n\n\t// ── Lower row ──────────────────────────────────────────────────────────\n\tconst lowerRow = el('div');\n\tcss_(lowerRow, {\n\t\tposition: 'relative',\n\t\theight: '28px',\n\t\twidth: `${totalWidth}px`,\n\t\tbackground: 'var(--gantt-header-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t});\n\n\tconst lowerNodes = lowerCells.map((cell) => {\n\t\tconst d = el('div');\n\t\tcss_(d, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${cell.x}px`,\n\t\t\twidth: `${cell.width}px`,\n\t\t\theight: '100%',\n\t\t\tborderRight: '1px solid var(--gantt-border)',\n\t\t\tdisplay: 'flex',\n\t\t\talignItems: 'center',\n\t\t\tjustifyContent: 'center',\n\t\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\toverflow: 'hidden',\n\t\t\twhiteSpace: 'nowrap',\n\t\t});\n\t\td.textContent = cell.label;\n\n\t\tif (scale === 'day') {\n\t\t\tconst kind = specialDayKind(cell.date, specialDaysByDate, showWeekends, weekendDays);\n\t\t\tif (kind !== null) {\n\t\t\t\td.classList.add(`gantt-header-cell--${kind}`);\n\t\t\t\tconst dateKey = startOfDay(cell.date).toISOString().slice(0, 10);\n\t\t\t\td.dataset['date'] = dateKey;\n\t\t\t\tconst specialDay = specialDaysByDate.get(dateKey);\n\t\t\t\tif (specialDay?.label !== undefined) {\n\t\t\t\t\td.dataset['label'] = specialDay.label;\n\t\t\t\t\td.title = specialDay.label;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn d;\n\t});\n\n\tappendAll(upperRow, upperNodes);\n\tappendAll(lowerRow, lowerNodes);\n\n\tclearChildren(container);\n\tcontainer.append(upperRow);\n\tcontainer.append(lowerRow);\n}\n","import {formatDisplayDate} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS} from '../../locale.ts';\nimport {type Task as GenTask} from '../../validation/schemas.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\n\n/**\n * Union of all field names that can appear on any {@link Task} variant.\n * Use when referencing task fields in grid column schemas that apply\n * across a heterogeneous set of task kinds.\n */\nexport type TaskDataField = keyof GenTask | 'endDate' | 'percentComplete' | 'open';\n\nexport type GridColumn = {\n\tid: string;\n\theader: string;\n\twidth: string;\n\talign?: 'left' | 'center' | 'right';\n\tvisible?: boolean;\n\tfield?: TaskDataField;\n\tformat?: (value: unknown, task: GenTask<Record<string, unknown>>, row: TaskNode, locale: ChartLocale) => string;\n};\n\nexport const DEFAULT_GRID_COLUMNS: GridColumn[] = [\n\t{\n\t\tid: 'name',\n\t\theader: 'Task name',\n\t\twidth: '1fr',\n\t},\n\t{\n\t\tid: 'startDate',\n\t\theader: 'Start',\n\t\twidth: '90px',\n\t\tfield: 'startDate',\n\t\tformat: (value, _task, _row, locale) => formatDisplayDate(value as string, locale),\n\t},\n\t{\n\t\tid: 'actions',\n\t\theader: '',\n\t\twidth: '28px',\n\t},\n];\n\n/**\n * Returns a localized default grid column schema.\n * Column headers use locale label overrides with `EN_US_LABELS` fallback.\n *\n * @param locale - The {@link ChartLocale} to derive column header labels from.\n * @returns An array of {@link GridColumn} objects.\n */\nexport function gridColumnDefaults(locale: ChartLocale): GridColumn[] {\n\treturn [\n\t\t{\n\t\t\tid: 'name',\n\t\t\theader: locale.labels?.columnTaskName ?? EN_US_LABELS.columnTaskName,\n\t\t\twidth: '1fr',\n\t\t},\n\t\t{\n\t\t\tid: 'startDate',\n\t\t\theader: locale.labels?.columnStartDate ?? EN_US_LABELS.columnStartDate,\n\t\t\twidth: '90px',\n\t\t\tfield: 'startDate',\n\t\t\tformat: (value, _task, _row, loc) => formatDisplayDate(String(value), loc),\n\t\t},\n\t\t{\n\t\t\tid: 'actions',\n\t\t\theader: '',\n\t\t\twidth: '28px',\n\t\t},\n\t];\n}\n\n/**\n * Builds a CSS `grid-template-columns` value from a column schema.\n *\n * @param columns - The full column schema array (only visible columns are included).\n * @returns A space-separated CSS track list.\n */\nexport function gridTemplateColumns(columns: GridColumn[]): string {\n\treturn columns\n\t\t.filter((c) => c.visible !== false)\n\t\t.map((c) => c.width)\n\t\t.join(' ');\n}\n\n/**\n * Filters a column schema to only visible columns.\n *\n * @param columns - The full column schema array.\n * @returns A new array containing only columns where `visible` is not `false`.\n */\nexport function visibleColumns(columns: GridColumn[]): GridColumn[] {\n\treturn columns.filter((c) => c.visible !== false);\n}\n\nexport const GRID_COLUMN_FR_MIN_WIDTH = 120;\n\nconst PX_RE = /^(\\d+(?:\\.\\d+)?)px$/u;\nconst FR_RE = /^(\\d+(?:\\.\\d+)?)fr$/u;\n\nfunction parseColumnMinWidth(width: string): number {\n\tconst trimmed = width.trim();\n\tconst pxMatch = PX_RE.exec(trimmed);\n\tif (pxMatch) {\n\t\treturn parseFloat(pxMatch[1] ?? '0');\n\t}\n\tconst frMatch = FR_RE.exec(trimmed);\n\tif (frMatch) {\n\t\treturn parseFloat(frMatch[1] ?? '0') * GRID_COLUMN_FR_MIN_WIDTH;\n\t}\n\treturn 0;\n}\n\n/**\n * Computes the minimum natural pixel width of a grid column schema.\n *\n * @param columns - The full column schema array.\n * @returns The sum of minimum widths: `px` columns sum directly, `fr` units contribute\n * `GRID_COLUMN_FR_MIN_WIDTH` px each.\n */\nexport function gridNaturalWidth(columns: GridColumn[]): number {\n\tlet total = 0;\n\tfor (const col of visibleColumns(columns)) {\n\t\ttotal += parseColumnMinWidth(col.width);\n\t}\n\treturn total;\n}\n","import {el, clearChildren, css} from './helpers.ts';\nimport {type GanttState} from '../state.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\nimport {type ZodTaskInferred as Task} from '../../validation/schemas.ts';\nimport {isParent} from '../../domain/tree.ts';\nimport {ROW_HEIGHT} from '../../timeline/layoutEngine.ts';\nimport {type GridColumn, gridTemplateColumns, visibleColumns} from './gridColumns.ts';\nimport {type ChartLocale, EN_US_LABELS} from '../../locale.ts';\n\nconst INDENT = 16;\nconst COLUMN_MIN_WIDTH = 30;\n\nexport type LeftPaneCallbacks = {\n\tonToggle: (id: number) => void;\n\tonTaskClick: (id: number) => void;\n\tonRowClick: (payload: {id: number; task: Task}) => void;\n\tonTaskDoubleClick: (payload: {id: number; task: Task}) => void;\n\tonTaskAdd: (id: number) => void;\n};\n\nexport function toTask(node: TaskNode): Task {\n\tconst base = {\n\t\tid: node.id,\n\t\ttext: node.text,\n\t\tstartDate: node.startDate,\n\t\t...(node.parent === undefined ? {} : {parent: node.parent}),\n\t\t...(node.color === undefined ? {} : {color: node.color}),\n\t\t...(node.data === undefined ? {} : {data: node.data}),\n\t};\n\n\tswitch (node.kind) {\n\t\tcase 'task': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'task',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t};\n\t\t}\n\t\tcase 'project': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'project',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t\topen: node.open,\n\t\t\t};\n\t\t}\n\t\tcase 'milestone': {\n\t\t\treturn {...base, kind: 'milestone'};\n\t\t}\n\t}\n}\n\nfunction getTaskField(task: Task, field: string): unknown {\n\tswitch (field) {\n\t\tcase 'endDate': {\n\t\t\treturn task.kind !== 'milestone' ? task.endDate : undefined;\n\t\t}\n\t\tcase 'percentComplete': {\n\t\t\treturn task.kind !== 'milestone' ? task.percentComplete : undefined;\n\t\t}\n\t\tcase 'open': {\n\t\t\treturn task.kind === 'project' ? task.open : undefined;\n\t\t}\n\t\tdefault: {\n\t\t\treturn (task as Record<string, unknown>)[field];\n\t\t}\n\t}\n}\n\nfunction buildTreeNameCell(row: TaskNode, expandedIds: Set<number>, cbs: LeftPaneCallbacks): HTMLElement {\n\tconst hasChildren = isParent(row);\n\tconst expanded = expandedIds.has(row.id);\n\n\tconst cell = el('div');\n\tcss(cell, {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tpaddingLeft: `${row.depth * INDENT}px`,\n\t\tgap: '4px',\n\t\toverflow: 'hidden',\n\t});\n\n\tif (hasChildren) {\n\t\tconst btn = el('button');\n\t\tbtn.className = 'gantt-toggle';\n\t\tbtn.textContent = expanded ? '\\u25BE' : '\\u25B8';\n\t\tcss(btn, {\n\t\t\twidth: '16px',\n\t\t\theight: '16px',\n\t\t\tdisplay: 'flex',\n\t\t\talignItems: 'center',\n\t\t\tjustifyContent: 'center',\n\t\t\tbackground: 'none',\n\t\t\tborder: 'none',\n\t\t\tcursor: 'pointer',\n\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\tpadding: '0',\n\t\t\tflexShrink: '0',\n\t\t});\n\t\tbtn.addEventListener('click', (e) => {\n\t\t\te.stopPropagation();\n\t\t\tcbs.onToggle(row.id);\n\t\t});\n\t\tcell.append(btn);\n\t} else {\n\t\tconst spacer = el('span');\n\t\tspacer.style.width = '16px';\n\t\tspacer.style.flexShrink = '0';\n\t\tcell.append(spacer);\n\t}\n\n\tconst label = el('span');\n\tcss(label, {\n\t\tfontSize: 'var(--gantt-font-size-md)',\n\t\tfontWeight: row.kind === 'project' ? 'var(--gantt-font-weight-bold)' : 'var(--gantt-font-weight-normal)',\n\t\tcolor: 'var(--gantt-text)',\n\t\toverflow: 'hidden',\n\t\ttextOverflow: 'ellipsis',\n\t\twhiteSpace: 'nowrap',\n\t});\n\tlabel.textContent = row.text;\n\tcell.append(label);\n\n\treturn cell;\n}\n\nfunction buildDataCell(row: TaskNode, column: GridColumn, locale: ChartLocale): HTMLElement {\n\tconst cell = el('span');\n\tconst styles: Partial<CSSStyleDeclaration> = {\n\t\tfontSize: 'var(--gantt-font-size-sm)',\n\t\tcolor: 'var(--gantt-text-secondary)',\n\t\tpaddingRight: '8px',\n\t\toverflow: 'hidden',\n\t\ttextOverflow: 'ellipsis',\n\t\twhiteSpace: 'nowrap',\n\t};\n\tif (column.align !== undefined) {\n\t\tstyles.textAlign = column.align;\n\t}\n\tcss(cell, styles);\n\n\tconst task = toTask(row);\n\tif (column.field !== undefined) {\n\t\tconst rawValue = getTaskField(task, column.field);\n\t\tif (column.format !== undefined) {\n\t\t\tcell.textContent = column.format(rawValue, task, row, locale);\n\t\t} else {\n\t\t\tcell.textContent =\n\t\t\t\trawValue !== null && rawValue !== undefined\n\t\t\t\t\t? typeof rawValue === 'object'\n\t\t\t\t\t\t? JSON.stringify(rawValue)\n\t\t\t\t\t\t: String(rawValue as string | number | boolean)\n\t\t\t\t\t: '';\n\t\t}\n\t}\n\n\treturn cell;\n}\n\nfunction buildAddButton(row: TaskNode, cbs: LeftPaneCallbacks, locale: ChartLocale): HTMLElement {\n\tconst btn = el('button');\n\tbtn.className = 'gantt-add-btn';\n\tbtn.textContent = '+';\n\tbtn.title = locale.labels?.addSubtaskTitle ?? EN_US_LABELS.addSubtaskTitle;\n\tcss(btn, {\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\tcolor: 'var(--gantt-text-secondary)',\n\t\tfontSize: 'var(--gantt-font-size-lg)',\n\t\tlineHeight: '1',\n\t});\n\tbtn.addEventListener('click', (event) => {\n\t\tevent.stopPropagation();\n\t\tcbs.onTaskAdd(row.id);\n\t});\n\n\treturn btn;\n}\n\nfunction buildActionsPlaceholder(): HTMLElement {\n\tconst div = el('div');\n\treturn div;\n}\n\nfunction buildCell(\n\tcolumn: GridColumn,\n\trow: TaskNode,\n\texpandedIds: Set<number>,\n\tcbs: LeftPaneCallbacks,\n\tlocale: ChartLocale,\n\tshowAddTaskButton: boolean,\n): HTMLElement {\n\tswitch (column.id) {\n\t\tcase 'name': {\n\t\t\treturn buildTreeNameCell(row, expandedIds, cbs);\n\t\t}\n\t\tcase 'actions': {\n\t\t\treturn showAddTaskButton ? buildAddButton(row, cbs, locale) : buildActionsPlaceholder();\n\t\t}\n\t\tdefault: {\n\t\t\treturn buildDataCell(row, column, locale);\n\t\t}\n\t}\n}\n\nfunction buildRow(\n\trow: TaskNode,\n\tselectedId: number | null,\n\texpandedIds: Set<number>,\n\tcbs: LeftPaneCallbacks,\n\tcolumns: GridColumn[],\n\tlocale: ChartLocale,\n\tshowAddTaskButton: boolean,\n): HTMLElement {\n\tconst selected = row.id === selectedId;\n\n\tconst wrapper = el('div');\n\twrapper.className = 'gantt-row';\n\tcss(wrapper, {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: gridTemplateColumns(columns),\n\t\theight: `${ROW_HEIGHT}px`,\n\t\talignItems: 'center',\n\t\tpaddingLeft: '8px',\n\t\tbackground: selected ? 'var(--gantt-row-selected)' : 'var(--gantt-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t\tcursor: 'default',\n\t\tboxSizing: 'border-box',\n\t});\n\twrapper.tabIndex = 0;\n\twrapper.setAttribute('role', 'row');\n\twrapper.setAttribute('aria-selected', String(selected));\n\twrapper.dataset['taskId'] = String(row.id);\n\twrapper.addEventListener('click', () => {\n\t\tconst task = toTask(row);\n\t\tcbs.onRowClick({id: row.id, task});\n\t});\n\twrapper.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onTaskClick(row.id);\n\t\t}\n\t});\n\n\tfor (const column of visibleColumns(columns)) {\n\t\twrapper.append(buildCell(column, row, expandedIds, cbs, locale, showAddTaskButton));\n\t}\n\n\treturn wrapper;\n}\n\n/**\n * Renders the left grid pane.\n *\n * @param container - The left pane body element to render into.\n * @param state - The current chart state.\n * @param cbs - The left pane callbacks.\n * @param columns - The grid column schema.\n * @param showAddTaskButton - Whether to render the add-subtask button in the actions column.\n */\nexport function renderLeftPane(container: HTMLElement, state: GanttState, cbs: LeftPaneCallbacks, columns: GridColumn[], showAddTaskButton = true): void {\n\tconst {allRows, selectedId, expandedIds, startIndex, endIndex, paddingTop, paddingBottom, locale} = state;\n\n\tconst frag = document.createDocumentFragment();\n\n\tif (paddingTop > 0) {\n\t\tconst spacer = el('div');\n\t\tspacer.style.height = `${paddingTop}px`;\n\t\tfrag.append(spacer);\n\t}\n\n\tfor (const row of allRows.slice(startIndex, endIndex + 1)) {\n\t\tfrag.append(buildRow(row, selectedId, expandedIds, cbs, columns, locale, showAddTaskButton));\n\t}\n\n\tif (paddingBottom > 0) {\n\t\tconst spacer = el('div');\n\t\tspacer.style.height = `${paddingBottom}px`;\n\t\tfrag.append(spacer);\n\t}\n\n\tclearChildren(container);\n\tcontainer.append(frag);\n}\n\n/**\n * Builds the header row for the left pane.\n *\n * @param columns - The grid column schema.\n * @param locale - The current chart locale.\n * @returns The header DOM element.\n */\nexport function buildLeftPaneHeader(columns: GridColumn[], locale: ChartLocale): HTMLElement {\n\tconst header = el('div');\n\tcss(header, {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: gridTemplateColumns(columns),\n\t\theight: '52px',\n\t\tbackground: 'var(--gantt-header-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t\tpaddingLeft: '8px',\n\t\talignItems: 'flex-end',\n\t\tpaddingBottom: '4px',\n\t\tboxSizing: 'border-box',\n\t});\n\n\tconst visible = visibleColumns(columns);\n\tfor (let i = 0; i < visible.length; i++) {\n\t\tconst column = visible[i];\n\t\tif (column === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst wrapper = el('div');\n\t\tcss(wrapper, {position: 'relative', display: 'flex', alignItems: 'flex-end'});\n\n\t\tif (i === 0 && visible[0]?.id === 'name') {\n\t\t\tconst btnContainer = el('div');\n\t\t\tbtnContainer.className = 'gantt-header-tree-controls';\n\t\t\tcss(btnContainer, {\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tgap: '4px',\n\t\t\t\tmarginRight: '6px',\n\t\t\t\tpaddingBottom: '1px',\n\t\t\t});\n\n\t\t\tconst expandBtn = el('button');\n\t\t\texpandBtn.className = 'gantt-header-expand-btn';\n\t\t\texpandBtn.textContent = '+';\n\t\t\texpandBtn.title = locale.labels?.expandAllTitle ?? EN_US_LABELS.expandAllTitle;\n\t\t\texpandBtn.setAttribute('aria-label', expandBtn.title);\n\t\t\tcss(expandBtn, {\n\t\t\t\twidth: '18px',\n\t\t\t\theight: '18px',\n\t\t\t\tdisplay: 'flex',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\tbackground: 'var(--gantt-header-bg)',\n\t\t\t\tborder: '1px solid var(--gantt-border)',\n\t\t\t\tborderRadius: '3px',\n\t\t\t\tcursor: 'pointer',\n\t\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\t\tfontSize: '14px',\n\t\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\t\tlineHeight: '1',\n\t\t\t\tpadding: '0',\n\t\t\t});\n\n\t\t\tconst collapseBtn = el('button');\n\t\t\tcollapseBtn.className = 'gantt-header-collapse-btn';\n\t\t\tcollapseBtn.textContent = '\\u2212';\n\t\t\tcollapseBtn.title = locale.labels?.collapseAllTitle ?? EN_US_LABELS.collapseAllTitle;\n\t\t\tcollapseBtn.setAttribute('aria-label', collapseBtn.title);\n\t\t\tcss(collapseBtn, {\n\t\t\t\twidth: '18px',\n\t\t\t\theight: '18px',\n\t\t\t\tdisplay: 'flex',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\tbackground: 'var(--gantt-header-bg)',\n\t\t\t\tborder: '1px solid var(--gantt-border)',\n\t\t\t\tborderRadius: '3px',\n\t\t\t\tcursor: 'pointer',\n\t\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\t\tfontSize: '14px',\n\t\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\t\tlineHeight: '1',\n\t\t\t\tpadding: '0',\n\t\t\t});\n\n\t\t\tbtnContainer.append(expandBtn, collapseBtn);\n\t\t\twrapper.append(btnContainer);\n\t\t}\n\n\t\tconst cell = el('span');\n\t\tcss(cell, {\n\t\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\tletterSpacing: 'var(--gantt-letter-spacing-wide)',\n\t\t\ttextTransform: 'uppercase',\n\t\t\tpaddingRight: '8px',\n\t\t});\n\t\tif (column.align !== undefined) {\n\t\t\tcell.style.textAlign = column.align;\n\t\t}\n\t\tcell.textContent = column.header;\n\t\twrapper.append(cell);\n\n\t\tif (i < visible.length - 1) {\n\t\t\tconst handle = el('div');\n\t\t\thandle.className = 'gantt-col-resize-handle';\n\t\t\tcss(handle, {\n\t\t\t\tposition: 'absolute',\n\t\t\t\tright: '-3px',\n\t\t\t\ttop: '0',\n\t\t\t\tbottom: '0',\n\t\t\t\twidth: '6px',\n\t\t\t\tcursor: 'col-resize',\n\t\t\t\tzIndex: '1',\n\t\t\t});\n\t\t\twrapper.append(handle);\n\t\t}\n\n\t\theader.append(wrapper);\n\t}\n\n\treturn header;\n}\n\nexport const COLUMN_RESIZE_MIN_WIDTH = COLUMN_MIN_WIDTH;\n\n/**\n * Wires up column resize interactions on header handles.\n * Must be called after the header is in the DOM (so `getBoundingClientRect` works).\n *\n * @param headerEl - The header element containing resize handles.\n * @param bodyEl - The body element whose rows share the column widths.\n * @param columns - The grid column schema (mutated in place on resize end).\n * @param onChange - Optional callback fired on drag end with updated columns.\n * @returns A cleanup function that removes all resize listeners.\n */\nexport function setupColumnResize(headerEl: HTMLElement, bodyEl: HTMLElement, columns: GridColumn[], onChange?: (columns: GridColumn[]) => void): () => void {\n\tconst handles = headerEl.querySelectorAll<HTMLElement>('.gantt-col-resize-handle');\n\tconst cleanups: (() => void)[] = [];\n\n\tfor (let colIndex = 0; colIndex < handles.length; colIndex++) {\n\t\tconst handle = handles.item(colIndex);\n\t\tif (handle === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst capturedColIndex = colIndex;\n\n\t\tconst onPointerDown = (e: PointerEvent): void => {\n\t\t\tif (e.button !== 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\n\t\t\tconst startX = e.clientX;\n\t\t\tconst cells = [...headerEl.children] as HTMLElement[];\n\t\t\tconst startWidths = cells.map((c) => c.getBoundingClientRect().width);\n\n\t\t\tconst onMove = (me: PointerEvent): void => {\n\t\t\t\tconst dx = me.clientX - startX;\n\t\t\t\tconst newWidths = [...startWidths];\n\n\t\t\t\tnewWidths[capturedColIndex] = Math.max(COLUMN_MIN_WIDTH, (startWidths[capturedColIndex] ?? 0) + dx);\n\n\t\t\t\tif (capturedColIndex + 1 < newWidths.length) {\n\t\t\t\t\tnewWidths[capturedColIndex + 1] = Math.max(COLUMN_MIN_WIDTH, (startWidths[capturedColIndex + 1] ?? 0) - dx);\n\t\t\t\t}\n\n\t\t\t\tconst template = newWidths.map((w) => `${Math.round(w)}px`).join(' ');\n\t\t\t\theaderEl.style.gridTemplateColumns = template;\n\n\t\t\t\tconst rows = bodyEl.querySelectorAll<HTMLElement>('[role=\"row\"]');\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\trow.style.gridTemplateColumns = template;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst onUp = (): void => {\n\t\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\t\twindow.removeEventListener('pointerup', onUp);\n\n\t\t\t\tconst finalCells = [...headerEl.children] as HTMLElement[];\n\t\t\t\tconst visible = visibleColumns(columns);\n\t\t\t\tfor (let i = 0; i < visible.length && i < finalCells.length; i++) {\n\t\t\t\t\tconst col = visible[i];\n\t\t\t\t\tconst cell = finalCells[i];\n\t\t\t\t\tif (col !== undefined && cell !== undefined) {\n\t\t\t\t\t\tconst w = cell.getBoundingClientRect().width;\n\t\t\t\t\t\tcol.width = `${Math.round(w)}px`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tonChange?.([...columns]);\n\t\t\t};\n\n\t\t\twindow.addEventListener('pointermove', onMove);\n\t\t\twindow.addEventListener('pointerup', onUp);\n\t\t};\n\n\t\thandle.addEventListener('pointerdown', onPointerDown);\n\t\tcleanups.push(() => {\n\t\t\thandle.removeEventListener('pointerdown', onPointerDown);\n\t\t});\n\t}\n\n\treturn () => {\n\t\tfor (const cleanup of cleanups) {\n\t\t\tcleanup();\n\t\t}\n\t};\n}\n","import {setAttrs} from './helpers.ts';\nimport {type RoutedLink} from '../../rendering/linkRouter.ts';\n\nconst NS = 'http://www.w3.org/2000/svg';\nconst ARROW_PATH = 'M 0 1 L 10 5 L 0 9 Z';\nconst ARROW_SIZE = 6;\n\ntype DependencyCallbacks = {\n\tonLinkClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonLinkDblClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n};\n\n/**\n * Creates the SVG overlay element. Call once; pass to updateDependencyLayer on each render.\n * Also creates a hidden ghost-line path used during link-creation drags.\n *\n * The SVG is initially zero-sized; `updateDependencyLayer` sets width/height each frame.\n *\n * @param _totalWidth - The total pixel width of the SVG viewport.\n * @param _totalHeight - The total pixel height of the SVG viewport.\n * @returns An `SVGSVGElement` ready to be inserted into the DOM.\n */\nexport function createDependencyLayer(_totalWidth: number, _totalHeight: number): SVGSVGElement {\n\tconst svg = document.createElementNS(NS, 'svg');\n\tObject.assign(svg.style, {\n\t\tposition: 'absolute',\n\t\ttop: '0',\n\t\tleft: '0',\n\t\tpointerEvents: 'none',\n\t\toverflow: 'visible',\n\t\tzIndex: '1',\n\t});\n\n\t// Arrow markers (created once, reused by all paths via xlink/href)\n\tconst defs = document.createElementNS(NS, 'defs');\n\n\tfor (const [id, color] of [\n\t\t['gantt-arrow', 'var(--gantt-link)'],\n\t\t['gantt-arrow-hi', 'var(--gantt-link-hi)'],\n\t] as const) {\n\t\tconst marker = document.createElementNS(NS, 'marker');\n\t\tsetAttrs(marker, {\n\t\t\tid,\n\t\t\tviewBox: '0 0 10 10',\n\t\t\trefX: '10',\n\t\t\trefY: '5',\n\t\t\tmarkerWidth: ARROW_SIZE,\n\t\t\tmarkerHeight: ARROW_SIZE,\n\t\t\torient: 'auto',\n\t\t});\n\t\tconst path = document.createElementNS(NS, 'path');\n\t\tsetAttrs(path, {d: ARROW_PATH, fill: color});\n\t\tmarker.append(path);\n\t\tdefs.append(marker);\n\t}\n\n\tsvg.append(defs);\n\n\t// Ghost line for link-creation drag (hidden by default)\n\tconst ghostPath = document.createElementNS(NS, 'path');\n\tsetAttrs(ghostPath, {\n\t\td: '',\n\t\tfill: 'none',\n\t\tstroke: 'var(--gantt-link)',\n\t\t'stroke-width': '1.5',\n\t\t'stroke-dasharray': '5 3',\n\t});\n\tghostPath.classList.add('gantt-ghost-line');\n\tghostPath.style.display = 'none';\n\tsvg.append(ghostPath);\n\n\treturn svg;\n}\n\n/**\n * Shows or updates the ghost line drawn during a link-creation drag.\n *\n * @param svg - The SVG dependency layer element.\n * @param x1 - Start X coordinate.\n * @param y1 - Start Y coordinate.\n * @param x2 - End X coordinate.\n * @param y2 - End Y coordinate.\n * @param valid - When `true`, the line is drawn solid with an arrow marker.\n */\nexport function showGhostLine(svg: SVGSVGElement, x1: number, y1: number, x2: number, y2: number, valid: boolean): void {\n\tconst ghost = svg.querySelector<SVGPathElement>('path.gantt-ghost-line');\n\tif (ghost === null) {\n\t\treturn;\n\t}\n\tsetAttrs(ghost, {\n\t\td: `M ${x1},${y1} L ${x2},${y2}`,\n\t});\n\tif (valid) {\n\t\tghost.removeAttribute('stroke-dasharray');\n\t} else {\n\t\tghost.setAttribute('stroke-dasharray', '5 3');\n\t}\n\tif (valid) {\n\t\tghost.setAttribute('marker-end', 'url(#gantt-arrow)');\n\t} else {\n\t\tghost.removeAttribute('marker-end');\n\t}\n\tghost.style.display = '';\n}\n\n/**\n * Hides the ghost line after a link-creation drag completes or is cancelled.\n *\n * @param svg - The SVG dependency layer element.\n */\nexport function hideGhostLine(svg: SVGSVGElement): void {\n\tconst ghost = svg.querySelector<SVGPathElement>('path.gantt-ghost-line');\n\tif (ghost !== null) {\n\t\tghost.style.display = 'none';\n\t\tghost.removeAttribute('marker-end');\n\t}\n}\n\n/**\n * Replaces all path elements in the SVG to reflect the current link set.\n * The `<defs>` node (first child) is preserved.\n *\n * @param svg - The SVG dependency layer element.\n * @param links - The array of routed links to render.\n * @param totalWidth - The total pixel width of the SVG viewport.\n * @param totalHeight - The total pixel height of the SVG viewport.\n * @param selectedTaskId - The currently selected task ID, or `null`.\n * @param highlightLinkedDependenciesOnSelect - When `true`, links connected to the selected task use highlight styling.\n * @param cbs - Optional callbacks for link click and double-click events.\n */\nexport function updateDependencyLayer(\n\tsvg: SVGSVGElement,\n\tlinks: RoutedLink[],\n\ttotalWidth: number,\n\ttotalHeight: number,\n\tselectedTaskId: number | null,\n\thighlightLinkedDependenciesOnSelect: boolean,\n\tcbs?: DependencyCallbacks,\n): void {\n\tsetAttrs(svg, {width: totalWidth, height: totalHeight});\n\n\tconst toRemove = [...svg.children].slice(1).filter((c) => !c.classList.contains('gantt-ghost-line'));\n\tfor (const node of toRemove) {\n\t\tsvg.removeChild(node);\n\t}\n\n\tconst ghost = svg.querySelector<SVGPathElement>('path.gantt-ghost-line');\n\n\tfor (const link of links) {\n\t\tconst {points} = link;\n\t\tif (points.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [first, ...rest] = points as [(typeof points)[0], ...(typeof points)[0][]];\n\t\tconst d = `M ${first.x},${first.y}${rest.map((p) => ` L ${p.x},${p.y}`).join('')}`;\n\n\t\tconst isRelated =\n\t\t\thighlightLinkedDependenciesOnSelect && selectedTaskId !== null && (link.sourceTaskId === selectedTaskId || link.targetTaskId === selectedTaskId);\n\n\t\tconst path = document.createElementNS(NS, 'path');\n\t\tsetAttrs(path, {\n\t\t\td,\n\t\t\tfill: 'none',\n\t\t\tstroke: isRelated ? 'var(--gantt-link-hi)' : 'var(--gantt-link)',\n\t\t\t'stroke-width': isRelated ? '1.8' : '1.5',\n\t\t\t'stroke-linejoin': 'round',\n\t\t\t'marker-end': isRelated ? 'url(#gantt-arrow-hi)' : 'url(#gantt-arrow)',\n\t\t\t'data-link-id': String(link.linkId),\n\t\t});\n\t\tpath.style.pointerEvents = 'visibleStroke';\n\t\tpath.style.cursor = 'pointer';\n\n\t\tpath.addEventListener('click', (event) => {\n\t\t\tif (event.detail === 1) {\n\t\t\t\tcbs?.onLinkClick?.({\n\t\t\t\t\tid: link.linkId,\n\t\t\t\t\tsource: link.sourceTaskId,\n\t\t\t\t\ttarget: link.targetTaskId,\n\t\t\t\t\ttype: link.type,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tpath.addEventListener('dblclick', (_event) => {\n\t\t\tcbs?.onLinkDblClick?.({\n\t\t\t\tid: link.linkId,\n\t\t\t\tsource: link.sourceTaskId,\n\t\t\t\ttarget: link.targetTaskId,\n\t\t\t\ttype: link.type,\n\t\t\t});\n\t\t});\n\n\t\tif (ghost !== null) {\n\t\t\tsvg.insertBefore(path, ghost);\n\t\t} else {\n\t\t\tsvg.append(path);\n\t\t}\n\t}\n}\n","import {type TaskNode} from '../../domain/tree.ts';\nimport {type PixelMapper} from '../../timeline/pixelMapper.ts';\nimport {parseDate, addDays} from '../../domain/dateMath.ts';\nimport {type ZodTaskInferred as Task} from '../../validation/schemas.ts';\n\ntype InternalCallbacks = {\n\tonTaskClick?: (id: number) => void;\n\tonTaskMove?: (payload: {id: number; startDate: Date}) => void;\n\tonTaskResize?: (payload: {id: number; endDate: string}) => void;\n\tonTaskDoubleClick?: (payload: {id: number; task: Task}) => void;\n\t_onTaskMoveFinal?: (payload: {id: number; startDate: Date}) => Promise<boolean>;\n\t_onTaskResizeFinal?: (payload: {id: number; endDate: string}) => Promise<boolean>;\n\tonTaskProgressDrag?: (payload: {id: number; percentComplete: number}) => void;\n\t_onTaskProgressDragFinal?: (payload: {id: number; percentComplete: number}) => Promise<boolean>;\n};\n\nexport function toTask(node: TaskNode): Task {\n\tconst base = {\n\t\tid: node.id,\n\t\ttext: node.text,\n\t\tstartDate: node.startDate,\n\t\t...(node.parent === undefined ? {} : {parent: node.parent}),\n\t\t...(node.color === undefined ? {} : {color: node.color}),\n\t\t...(node.readonly === undefined ? {} : {readonly: node.readonly}),\n\t\t...(node.data === undefined ? {} : {data: node.data}),\n\t};\n\n\tswitch (node.kind) {\n\t\tcase 'task': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'task',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t};\n\t\t}\n\t\tcase 'project': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'project',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t\topen: node.open,\n\t\t\t};\n\t\t}\n\t\tcase 'milestone': {\n\t\t\treturn {...base, kind: 'milestone'};\n\t\t}\n\t}\n}\n\n/**\n * Attaches drag-to-move and resize listeners to a bar element.\n *\n * Design: all mutable state lives in closure variables captured at mousedown.\n * No global state; multiple bars can be dragged independently (one at a time).\n *\n * @param barEl - The bar DOM element.\n * @param resizeHandleEl - The resize handle DOM element.\n * @param task - The {@link TaskNode} for this bar.\n * @param getMapper - A function returning the current {@link PixelMapper} (snapshotted at mousedown).\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachDrag(barEl: HTMLElement, resizeHandleEl: HTMLElement, task: TaskNode, getMapper: () => PixelMapper, cbs: InternalCallbacks): () => void {\n\tfunction onBarDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\ttry {\n\t\t\tbarEl.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\t\tcbs.onTaskClick?.(task.id);\n\n\t\tconst startX = e.clientX;\n\t\tconst originDate = parseDate(task.startDate);\n\t\tconst mapper = getMapper();\n\n\t\tlet lastDays = 0;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tlastDays = Math.round(mapper.widthToDurationDays(dx));\n\t\t\tcbs.onTaskMove?.({id: task.id, startDate: addDays(originDate, lastDays)});\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tbarEl.style.cursor = 'grab';\n\t\t\tif (lastDays !== 0) {\n\t\t\t\tvoid cbs._onTaskMoveFinal?.({id: task.id, startDate: addDays(originDate, lastDays)});\n\t\t\t}\n\t\t}\n\n\t\tbarEl.style.cursor = 'grabbing';\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tfunction onResizeDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\ttry {\n\t\t\tresizeHandleEl.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\n\t\tconst startX = e.clientX;\n\t\tif (task.kind === 'milestone') {\n\t\t\treturn;\n\t\t}\n\t\tconst origEnd = parseDate(task.endDate);\n\t\tconst mapper = getMapper();\n\n\t\tlet lastEnd = origEnd;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst daysDelta = Math.round(mapper.widthToDurationDays(dx));\n\t\t\tlastEnd = addDays(origEnd, daysDelta);\n\t\t\tcbs.onTaskResize?.({id: task.id, endDate: lastEnd.toISOString().slice(0, 10)});\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tvoid cbs._onTaskResizeFinal?.({id: task.id, endDate: lastEnd.toISOString().slice(0, 10)});\n\t\t}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tbarEl.addEventListener('pointerdown', onBarDown);\n\tresizeHandleEl.addEventListener('pointerdown', onResizeDown);\n\n\treturn () => {\n\t\tbarEl.removeEventListener('pointerdown', onBarDown);\n\t\tresizeHandleEl.removeEventListener('pointerdown', onResizeDown);\n\t};\n}\n\n/**\n * Attaches drag-to-change-progress listeners to a progress overlay element.\n *\n * @param progressEl - The progress overlay DOM element.\n * @param barEl - The bar DOM element (for width measurement).\n * @param task - The {@link TaskNode} for this bar.\n * @param _getMapper - A function returning the current {@link PixelMapper} (unused, kept for API symmetry).\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachProgressDrag(\n\tprogressEl: HTMLElement,\n\tbarEl: HTMLElement,\n\ttask: TaskNode,\n\t_getMapper: () => PixelMapper,\n\tcbs: InternalCallbacks,\n): () => void {\n\tfunction onProgressDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tcbs.onTaskClick?.(task.id);\n\t\ttry {\n\t\t\tprogressEl.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\n\t\tconst startX = e.clientX;\n\t\tconst barWidth = barEl.getBoundingClientRect().width;\n\t\tconst origPercent = task.kind !== 'milestone' ? (task.percentComplete ?? 0) : 0;\n\n\t\tlet lastPercent = origPercent;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst percentDelta = barWidth > 0 ? (dx / barWidth) * 100 : 0;\n\t\t\tlastPercent = Math.max(0, Math.min(100, Math.round(origPercent + percentDelta)));\n\t\t\tcbs.onTaskProgressDrag?.({id: task.id, percentComplete: lastPercent});\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tprogressEl.style.cursor = 'ew-resize';\n\t\t\tvoid cbs._onTaskProgressDragFinal?.({id: task.id, percentComplete: lastPercent});\n\t\t}\n\n\t\tprogressEl.style.cursor = 'ew-resize';\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tprogressEl.addEventListener('pointerdown', onProgressDown);\n\n\treturn () => {\n\t\tprogressEl.removeEventListener('pointerdown', onProgressDown);\n\t};\n}\n\n/**\n * Attaches click-to-select on a milestone diamond.\n *\n * @param diamondEl - The milestone diamond DOM element.\n * @param taskId - The task ID to select.\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachMilestoneClick(diamondEl: HTMLElement, taskId: number, cbs: InternalCallbacks): () => void {\n\tfunction onClick(): void {\n\t\tcbs.onTaskClick?.(taskId);\n\t}\n\tfunction onDoubleClick(event: MouseEvent): void {\n\t\tif (event.detail === 2) {\n\t\t\tconst task = (diamondEl as HTMLElement & {__task?: Task}).__task;\n\t\t\tif (task === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcbs.onTaskDoubleClick?.({id: taskId, task});\n\t\t}\n\t}\n\tdiamondEl.addEventListener('click', onClick);\n\tdiamondEl.addEventListener('click', onDoubleClick);\n\treturn () => {\n\t\tdiamondEl.removeEventListener('click', onClick);\n\t\tdiamondEl.removeEventListener('click', onDoubleClick);\n\t};\n}\n\nexport function bindMilestoneTask(diamondEl: HTMLElement, task: Task): void {\n\t(diamondEl as HTMLElement & {__task?: Task}).__task = task;\n}\n","import {showGhostLine, hideGhostLine} from '../dom/dependencyLayer.ts';\n\ntype LinkCreationCallbacks = {\n\tonLinkCreate?: (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n};\n\n/**\n * Attaches a link-creation drag listener to an endpoint handle.\n *\n * @param handle - The endpoint DOM element.\n * @param sourceTaskId - The task ID from which the link originates.\n * @param anchorX - The X anchor coordinate (task center).\n * @param anchorY - The Y anchor coordinate (task center).\n * @param svgLayer - The SVG dependency layer element for ghost line rendering.\n * @param absoluteLayer - The absolute-positioned layer for coordinate calculations.\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachLinkEndpointHandle(\n\thandle: HTMLElement,\n\tsourceTaskId: number,\n\tanchorX: number,\n\tanchorY: number,\n\tsvgLayer: SVGSVGElement,\n\tabsoluteLayer: HTMLElement,\n\tcbs: LinkCreationCallbacks,\n): () => void {\n\tfunction onPointerDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\ttry {\n\t\t\thandle.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\n\t\tlet validTargetId: number | null = null;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst layerRect = absoluteLayer.getBoundingClientRect();\n\t\t\tconst x = me.clientX - layerRect.left;\n\t\t\tconst y = me.clientY - layerRect.top;\n\n\t\t\t// Hit-test for bars and milestones\n\t\t\tconst el = document.elementFromPoint(me.clientX, me.clientY);\n\t\t\tconst barEl = el?.closest<HTMLElement>('[data-task-id]');\n\t\t\tconst targetId = barEl !== null && barEl !== undefined ? Number(barEl.dataset['taskId']) : null;\n\n\t\t\tvalidTargetId = targetId !== null && targetId !== sourceTaskId ? targetId : null;\n\n\t\t\tshowGhostLine(svgLayer, anchorX, anchorY, x, y, validTargetId !== null);\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\thideGhostLine(svgLayer);\n\n\t\t\tif (validTargetId !== null) {\n\t\t\t\tcbs.onLinkCreate?.({sourceTaskId, targetTaskId: validTargetId, type: 'FS'});\n\t\t\t}\n\t\t}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\thandle.addEventListener('pointerdown', onPointerDown);\n\thandle.tabIndex = 0;\n\thandle.setAttribute('role', 'button');\n\thandle.setAttribute('aria-label', `Create link from task ${sourceTaskId}`);\n\n\tfunction onKeyDown(event: KeyboardEvent): void {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\thandle.addEventListener('keydown', onKeyDown);\n\n\treturn () => {\n\t\thandle.removeEventListener('pointerdown', onPointerDown);\n\t\thandle.removeEventListener('keydown', onKeyDown);\n\t};\n}\n\n/**\n * Creates an endpoint handle DOM element.\n * The caller must position it with inline styles and append it to the layer.\n *\n * @returns A new `HTMLElement` with the `gantt-link-endpoint` class.\n */\nexport function createEndpointHandle(): HTMLElement {\n\tconst handle = document.createElement('div');\n\thandle.className = 'gantt-link-endpoint';\n\thandle.style.position = 'absolute';\n\thandle.style.width = '10px';\n\thandle.style.height = '10px';\n\thandle.style.borderRadius = '50%';\n\thandle.style.background = 'var(--gantt-link)';\n\thandle.style.border = '2px solid var(--gantt-bg)';\n\thandle.style.cursor = 'crosshair';\n\thandle.style.zIndex = '4';\n\thandle.style.opacity = '0';\n\thandle.style.transition = 'opacity 0.15s ease, transform 0.1s ease';\n\thandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\thandle.style.pointerEvents = 'auto';\n\thandle.style.touchAction = 'none';\n\treturn handle;\n}\n","import {el, css, clearChildren} from './helpers.ts';\nimport {createDependencyLayer, updateDependencyLayer, hideGhostLine} from './dependencyLayer.ts';\nimport {attachDrag, attachMilestoneClick, bindMilestoneTask, attachProgressDrag, toTask} from '../interaction/drag.ts';\nimport {attachLinkEndpointHandle, createEndpointHandle} from '../interaction/linkCreation.ts';\nimport {type GanttState} from '../state.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\nimport {type BarLayout} from '../../timeline/layoutEngine.ts';\nimport {ROW_HEIGHT, MILESTONE_HALF, totalContentHeight} from '../../timeline/layoutEngine.ts';\nimport {nextScaleBoundary, snapToScaleBoundary} from '../../timeline/scale.ts';\nimport {startOfDay} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS, formatLabel} from '../../locale.ts';\nimport {type ZodTaskInferred as Task} from '../../validation/schemas.ts';\n\ntype RightPaneCallbacks = {\n\tonTaskClick?: (id: number) => void;\n\tonTaskMove?: (payload: {id: number; startDate: Date}) => void;\n\tonTaskResize?: (payload: {id: number; endDate: string}) => void;\n\tonTaskEditIntent?: (payload: {id: number; source: 'grid' | 'bar' | 'milestone'; trigger: 'doubleClick'; task: Task}) => void;\n\tonTaskDoubleClick?: (payload: {id: number; task: Task}) => void;\n\tonLinkCreate?: (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n\tonLinkClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonLinkDblClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\t_onTaskMoveFinal?: (payload: {id: number; startDate: Date}) => Promise<boolean>;\n\t_onTaskResizeFinal?: (payload: {id: number; endDate: string}) => Promise<boolean>;\n\tonTaskProgressDrag?: (payload: {id: number; percentComplete: number}) => void;\n\t_onTaskProgressDragFinal?: (payload: {id: number; percentComplete: number}) => Promise<boolean>;\n\tonTooltipText?: (payload: {id: number; task: Task}) => string | null;\n};\n\nconst BAR_COLOR: Record<string, string> = {\n\ttask: 'var(--gantt-task)',\n\tproject: 'var(--gantt-project)',\n\tmilestone: 'var(--gantt-milestone)',\n};\n\n/**\n * Persistent DOM references for the right pane.\n * Created once in mount.ts; updated cheaply on each render.\n */\nexport type RightPaneRefs = {\n\tscrollContainer: HTMLElement;\n\tstripeContainer: HTMLElement;\n\tabsoluteLayer: HTMLElement;\n\tsvgLayer: SVGSVGElement;\n\ttooltipEl: HTMLElement;\n\t/** Map of taskId → {bar, resizeHandle, cleanupDrag} for update-in-place */\n\tbarRegistry: Map<\n\t\tnumber,\n\t\t{\n\t\t\tbar: HTMLElement;\n\t\t\tresizeHandle: HTMLElement;\n\t\t\tcleanupDrag?: () => void;\n\t\t\tcleanupLinkHandles?: () => void;\n\t\t\tcleanupProgressDrag?: () => void;\n\t\t\tcleanupTooltip?: () => void;\n\t\t}\n\t>;\n};\n\n/**\n * Creates the skeleton DOM structure for the right pane. Call once.\n *\n * @returns A new {@link RightPaneRefs} with empty containers and bar registry.\n */\nexport function createRightPaneRefs(): RightPaneRefs {\n\tconst scrollContainer = el('div');\n\tconst stripeContainer = el('div');\n\tconst absoluteLayer = el('div');\n\tconst svgLayer = createDependencyLayer(0, 0);\n\n\tcss(stripeContainer, {position: 'relative'});\n\tcss(absoluteLayer, {position: 'absolute', top: '52px', left: '0'});\n\n\tscrollContainer.append(stripeContainer);\n\tscrollContainer.append(absoluteLayer);\n\tabsoluteLayer.append(svgLayer);\n\n\tconst tooltipEl = el('div');\n\ttooltipEl.className = 'gantt-tooltip';\n\ttooltipEl.style.display = 'none';\n\tscrollContainer.append(tooltipEl);\n\n\treturn {\n\t\tscrollContainer,\n\t\tstripeContainer,\n\t\tabsoluteLayer,\n\t\tsvgLayer,\n\t\ttooltipEl,\n\t\tbarRegistry: new Map(),\n\t};\n}\n\nfunction ariaLabel(locale: ChartLocale, key: 'ariaTask' | 'ariaMilestone', arg: string): string {\n\tconst template = locale.labels?.[key] ?? EN_US_LABELS[key];\n\treturn formatLabel(template, arg);\n}\n\nfunction renderSpecialDayBackgrounds(layer: HTMLElement, beforeNode: Element, state: GanttState, contentHeight: number): void {\n\tconst {mapper, viewportStart, viewportEnd, showWeekends, weekendDays, specialDaysByDate} = state;\n\tlet cur = startOfDay(viewportStart);\n\n\twhile (cur < viewportEnd) {\n\t\tconst next = new Date(cur.getTime() + 86_400_000);\n\t\tconst x = mapper.toX(cur);\n\t\tconst width = Math.max(1, mapper.toX(next) - x);\n\t\tconst dateKey = cur.toISOString().slice(0, 10);\n\t\tconst specialDay = specialDaysByDate.get(dateKey);\n\t\tconst isWeekend = weekendDays.has(cur.getUTCDay());\n\n\t\tlet kind: 'weekend' | 'holiday' | 'custom' | null = null;\n\t\tif (specialDay !== undefined) {\n\t\t\tconst {kind: specialKind} = specialDay;\n\t\t\tkind = specialKind;\n\t\t} else if (showWeekends && isWeekend) {\n\t\t\tkind = 'weekend';\n\t\t}\n\n\t\tif (kind !== null) {\n\t\t\tconst dayCell = el('div');\n\t\t\tdayCell.className = `gantt-day-cell gantt-day-cell--${kind}`;\n\t\t\tif (specialDay?.className !== undefined) {\n\t\t\t\tdayCell.classList.add(specialDay.className);\n\t\t\t}\n\t\t\tdayCell.dataset['date'] = dateKey;\n\t\t\tif (specialDay?.label !== undefined) {\n\t\t\t\tdayCell.dataset['label'] = specialDay.label;\n\t\t\t\tdayCell.title = specialDay.label;\n\t\t\t}\n\t\t\tcss(dayCell, {\n\t\t\t\tposition: 'absolute',\n\t\t\t\tleft: `${x}px`,\n\t\t\t\ttop: '0',\n\t\t\t\twidth: `${width}px`,\n\t\t\t\theight: `${contentHeight}px`,\n\t\t\t\tpointerEvents: 'none',\n\t\t\t\tzIndex: '1',\n\t\t\t});\n\t\t\tlayer.insertBefore(dayCell, beforeNode);\n\t\t}\n\n\t\tcur = next;\n\t}\n}\n\n// ─── Bar ─────────────────────────────────────────────────────────────────────\n\nfunction renderBar(\n\tlayer: HTMLElement,\n\tsvgLayer: SVGSVGElement,\n\ttask: TaskNode,\n\tlayout: BarLayout,\n\tselectedId: number | null,\n\tregistry: RightPaneRefs['barRegistry'],\n\tstate: GanttState,\n\tcbs: RightPaneCallbacks,\n\ttooltipEl: HTMLElement,\n): void {\n\tconst selected = task.id === selectedId;\n\tconst readonly = task.readonly === true;\n\tconst color = BAR_COLOR[layout.kind] ?? BAR_COLOR['task'];\n\n\tconst bar = el('div');\n\tbar.className = `gantt-bar${selected ? ' gantt-bar--selected gantt-shape--selected' : ''}`;\n\tcss(bar, {\n\t\tposition: 'absolute',\n\t\tleft: `${layout.x}px`,\n\t\ttop: `${layout.y}px`,\n\t\twidth: `${layout.width}px`,\n\t\theight: `${layout.height}px`,\n\t\t...(color === undefined ? {} : {background: color}),\n\t\tborderRadius: layout.kind === 'project' ? '3px' : '4px',\n\t\tcursor: readonly ? 'pointer' : 'grab',\n\t\tuserSelect: 'none',\n\t\toverflow: 'hidden',\n\t\tzIndex: selected ? '3' : '2',\n\t\ttouchAction: 'none',\n\t});\n\n\t// Progress overlay\n\tlet cleanupProgressDrag: (() => void) | undefined;\n\tif (layout.progressWidth > 0) {\n\t\tconst prog = el('div');\n\t\tconst progressEnabled = state.progressDragEnabled;\n\t\tcss(prog, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: '0',\n\t\t\ttop: '0',\n\t\t\twidth: `${layout.progressWidth}px`,\n\t\t\theight: '100%',\n\t\t\tbackground: 'rgba(0,0,0,0.18)',\n\t\t\t...(progressEnabled ? {cursor: 'ew-resize', touchAction: 'none'} : {pointerEvents: 'none'}),\n\t\t});\n\t\tif (progressEnabled) {\n\t\t\tprog.className = 'gantt-progress-overlay';\n\t\t\tcleanupProgressDrag = attachProgressDrag(prog, bar, task, () => state.mapper, cbs);\n\t\t}\n\t\tbar.append(prog);\n\t}\n\n\t// Label\n\tconst label = el('span');\n\tcss(label, {\n\t\tposition: 'absolute',\n\t\tleft: '8px',\n\t\tright: '8px',\n\t\ttop: '50%',\n\t\ttransform: 'translateY(-50%)',\n\t\toverflow: 'hidden',\n\t\ttextOverflow: 'ellipsis',\n\t\tcolor: 'var(--gantt-bar-label-color)',\n\t\tfontSize: 'var(--gantt-font-size-sm)',\n\t\tfontWeight: 'var(--gantt-font-weight-semibold)',\n\t\twhiteSpace: 'nowrap',\n\t\tpointerEvents: 'none',\n\t\ttextShadow: '0 1px 2px rgba(0,0,0,0.25)',\n\t});\n\tlabel.textContent = task.text;\n\tbar.append(label);\n\tbar.tabIndex = 0;\n\tbar.setAttribute('role', 'button');\n\tbar.setAttribute('aria-label', ariaLabel(state.locale, 'ariaTask', task.text));\n\tbar.setAttribute('aria-pressed', String(selected));\n\tbar.dataset['taskId'] = String(task.id);\n\tbar.addEventListener('click', (event) => {\n\t\tif (event.detail === 2) {\n\t\t\tcbs.onTaskDoubleClick?.({id: task.id, task: toTask(task)});\n\t\t} else {\n\t\t\tcbs.onTaskClick?.(task.id);\n\t\t}\n\t});\n\tbar.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onTaskClick?.(task.id);\n\t\t}\n\t});\n\n\tlet handle: HTMLElement | undefined;\n\tlet cleanupDrag: (() => void) | undefined;\n\n\tif (!readonly) {\n\t\t// Resize handle\n\t\thandle = el('div');\n\t\thandle.className = 'gantt-resize-handle';\n\t\tcss(handle, {\n\t\t\tposition: 'absolute',\n\t\t\tright: '0',\n\t\t\ttop: '0',\n\t\t\twidth: '8px',\n\t\t\theight: '100%',\n\t\t\tcursor: 'ew-resize',\n\t\t\tzIndex: '1',\n\t\t\ttouchAction: 'none',\n\t\t});\n\t\tbar.append(handle);\n\n\t\tlayer.insertBefore(bar, svgLayer);\n\t\tcleanupDrag = attachDrag(bar, handle, task, () => state.mapper, cbs);\n\t} else {\n\t\tlayer.insertBefore(bar, svgLayer);\n\t}\n\n\t// Link-creation endpoint handles\n\tlet cleanupLinkHandles: (() => void) | undefined;\n\tif (state.linkCreationEnabled) {\n\t\tconst barCenterY = layout.y + layout.height / 2;\n\t\tconst leftHandle = createEndpointHandle();\n\t\tleftHandle.style.left = `${layout.x}px`;\n\t\tleftHandle.style.top = `${barCenterY}px`;\n\t\tlayer.insertBefore(leftHandle, svgLayer);\n\n\t\tconst rightHandle = createEndpointHandle();\n\t\trightHandle.style.left = `${layout.x + layout.width}px`;\n\t\trightHandle.style.top = `${barCenterY}px`;\n\t\tlayer.insertBefore(rightHandle, svgLayer);\n\n\t\tconst cleanupLeft = attachLinkEndpointHandle(leftHandle, task.id, layout.x, barCenterY, svgLayer, layer, cbs);\n\t\tconst cleanupRight = attachLinkEndpointHandle(rightHandle, task.id, layout.x + layout.width, barCenterY, svgLayer, layer, cbs);\n\n\t\t// Show handles on bar hover\n\t\tconst onBarEnter = (): void => {\n\t\t\tleftHandle.style.opacity = '1';\n\t\t\trightHandle.style.opacity = '1';\n\t\t\tleftHandle.style.transform = 'translate(-50%, -50%) scale(1)';\n\t\t\trightHandle.style.transform = 'translate(-50%, -50%) scale(1)';\n\t\t};\n\t\tconst onBarLeave = (): void => {\n\t\t\tleftHandle.style.opacity = '0';\n\t\t\trightHandle.style.opacity = '0';\n\t\t\tleftHandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\t\t\trightHandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\t\t};\n\t\tbar.addEventListener('mouseenter', onBarEnter);\n\t\tbar.addEventListener('mouseleave', onBarLeave);\n\n\t\tcleanupLinkHandles = (): void => {\n\t\t\tcleanupLeft();\n\t\t\tcleanupRight();\n\t\t\tbar.removeEventListener('mouseenter', onBarEnter);\n\t\t\tbar.removeEventListener('mouseleave', onBarLeave);\n\t\t};\n\t}\n\n\t// Tooltip\n\tconst onTooltipEnter = (): void => {\n\t\tconst content = cbs.onTooltipText?.({id: task.id, task: toTask(task)});\n\t\tif (content && content.length > 0) {\n\t\t\ttooltipEl.innerHTML = content;\n\t\t\ttooltipEl.style.display = '';\n\t\t} else {\n\t\t\ttooltipEl.style.display = 'none';\n\t\t}\n\t};\n\tconst onTooltipMove = (e: MouseEvent): void => {\n\t\tconst offsetX = 12;\n\t\tconst offsetY = -8;\n\t\tlet left = e.clientX + offsetX;\n\t\tlet top = e.clientY + offsetY;\n\t\tconst maxLeft = window.innerWidth - tooltipEl.offsetWidth - 4;\n\t\tconst maxTop = window.innerHeight - tooltipEl.offsetHeight - 4;\n\t\tleft = Math.max(4, Math.min(left, maxLeft));\n\t\ttop = Math.max(4, Math.min(top, maxTop));\n\t\ttooltipEl.style.left = `${left}px`;\n\t\ttooltipEl.style.top = `${top}px`;\n\t};\n\tconst onTooltipLeave = (): void => {\n\t\ttooltipEl.style.display = 'none';\n\t};\n\tbar.addEventListener('mouseenter', onTooltipEnter);\n\tbar.addEventListener('mousemove', onTooltipMove);\n\tbar.addEventListener('mouseleave', onTooltipLeave);\n\tconst cleanupTooltip = (): void => {\n\t\tbar.removeEventListener('mouseenter', onTooltipEnter);\n\t\tbar.removeEventListener('mousemove', onTooltipMove);\n\t\tbar.removeEventListener('mouseleave', onTooltipLeave);\n\t};\n\n\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag?: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t\tcleanupProgressDrag?: () => void;\n\t\tcleanupTooltip?: () => void;\n\t} = {bar, resizeHandle: handle ?? el('div')};\n\tif (cleanupDrag !== undefined) {\n\t\tentry.cleanupDrag = cleanupDrag;\n\t}\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\n\t}\n\tif (cleanupProgressDrag !== undefined) {\n\t\tentry.cleanupProgressDrag = cleanupProgressDrag;\n\t}\n\tif (cleanupTooltip !== undefined) {\n\t\tentry.cleanupTooltip = cleanupTooltip;\n\t}\n\tregistry.set(task.id, entry);\n}\n\n// ─── Milestone ────────────────────────────────────────────────────────────────\n\nfunction renderMilestone(\n\tlayer: HTMLElement,\n\tsvgLayer: SVGSVGElement,\n\ttask: TaskNode,\n\tlayout: BarLayout,\n\tselectedId: number | null,\n\tregistry: RightPaneRefs['barRegistry'],\n\tcbs: RightPaneCallbacks,\n\tstate: GanttState,\n\ttooltipEl: HTMLElement,\n): void {\n\tconst selected = task.id === selectedId;\n\tconst readonly = task.readonly === true;\n\tconst size = MILESTONE_HALF * 2;\n\n\tconst diamond = el('div');\n\tdiamond.className = `gantt-milestone${selected ? ' gantt-shape--selected' : ''}`;\n\tcss(diamond, {\n\t\tposition: 'absolute',\n\t\tleft: `${layout.x - MILESTONE_HALF}px`,\n\t\ttop: `${layout.y + (layout.height - size) / 2}px`,\n\t\twidth: `${size}px`,\n\t\theight: `${size}px`,\n\t\tbackground: 'var(--gantt-milestone)',\n\t\ttransform: 'rotate(45deg)',\n\t\tcursor: readonly ? 'default' : 'pointer',\n\t\tzIndex: '4',\n\t});\n\tdiamond.tabIndex = 0;\n\tdiamond.setAttribute('role', 'button');\n\tdiamond.setAttribute('aria-label', ariaLabel(state.locale, 'ariaMilestone', task.text));\n\tdiamond.setAttribute('aria-pressed', String(selected));\n\tdiamond.dataset['taskId'] = String(task.id);\n\tdiamond.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onTaskClick?.(task.id);\n\t\t}\n\t});\n\tconst labelEl = el('span');\n\tcss(labelEl, {\n\t\tposition: 'absolute',\n\t\tleft: '50%',\n\t\ttop: '110%',\n\t\ttransform: 'translate(-50%, 0) rotate(-45deg)',\n\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\tfontWeight: 'var(--gantt-font-weight-semibold)',\n\t\tcolor: 'var(--gantt-milestone)',\n\t\twhiteSpace: 'nowrap',\n\t\tpointerEvents: 'none',\n\t});\n\tlabelEl.textContent = task.text;\n\tdiamond.append(labelEl);\n\n\tlayer.insertBefore(diamond, svgLayer);\n\tbindMilestoneTask(diamond, task);\n\n\t// Milestones have no resize handle — use a dummy div for the registry interface\n\tconst dummy = el('div');\n\tlet cleanupDrag: (() => void) | undefined;\n\n\tif (!readonly) {\n\t\tcleanupDrag = attachMilestoneClick(diamond, task.id, cbs);\n\t} else {\n\t\tdiamond.addEventListener('click', (event) => {\n\t\t\tif (event.detail === 2) {\n\t\t\t\tcbs.onTaskDoubleClick?.({id: task.id, task: toTask(task)});\n\t\t\t} else {\n\t\t\t\tcbs.onTaskClick?.(task.id);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Link-creation endpoint handle for milestones (single handle at center)\n\tlet cleanupLinkHandles: (() => void) | undefined;\n\tif (state.linkCreationEnabled) {\n\t\tconst diamondCenterY = layout.y + layout.height / 2;\n\t\tconst linkHandle = createEndpointHandle();\n\t\tlinkHandle.style.left = `${layout.x}px`;\n\t\tlinkHandle.style.top = `${diamondCenterY}px`;\n\t\tlinkHandle.style.background = 'var(--gantt-milestone)';\n\t\tlayer.insertBefore(linkHandle, svgLayer);\n\n\t\tconst cleanupLink = attachLinkEndpointHandle(linkHandle, task.id, layout.x, diamondCenterY, svgLayer, layer, cbs);\n\n\t\tconst onDiamondEnter = (): void => {\n\t\t\tlinkHandle.style.opacity = '1';\n\t\t\tlinkHandle.style.transform = 'translate(-50%, -50%) scale(1)';\n\t\t};\n\t\tconst onDiamondLeave = (): void => {\n\t\t\tlinkHandle.style.opacity = '0';\n\t\t\tlinkHandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\t\t};\n\t\tdiamond.addEventListener('mouseenter', onDiamondEnter);\n\t\tdiamond.addEventListener('mouseleave', onDiamondLeave);\n\n\t\tcleanupLinkHandles = (): void => {\n\t\t\tcleanupLink();\n\t\t\tdiamond.removeEventListener('mouseenter', onDiamondEnter);\n\t\t\tdiamond.removeEventListener('mouseleave', onDiamondLeave);\n\t\t};\n\t}\n\n\t// Tooltip\n\tconst onTooltipEnter = (): void => {\n\t\tconst content = cbs.onTooltipText?.({id: task.id, task: toTask(task)});\n\t\tif (content && content.length > 0) {\n\t\t\ttooltipEl.innerHTML = content;\n\t\t\ttooltipEl.style.display = '';\n\t\t} else {\n\t\t\ttooltipEl.style.display = 'none';\n\t\t}\n\t};\n\tconst onTooltipMove = (e: MouseEvent): void => {\n\t\tconst offsetX = 12;\n\t\tconst offsetY = -8;\n\t\tlet left = e.clientX + offsetX;\n\t\tlet top = e.clientY + offsetY;\n\t\tconst maxLeft = window.innerWidth - tooltipEl.offsetWidth - 4;\n\t\tconst maxTop = window.innerHeight - tooltipEl.offsetHeight - 4;\n\t\tleft = Math.max(4, Math.min(left, maxLeft));\n\t\ttop = Math.max(4, Math.min(top, maxTop));\n\t\ttooltipEl.style.left = `${left}px`;\n\t\ttooltipEl.style.top = `${top}px`;\n\t};\n\tconst onTooltipLeave = (): void => {\n\t\ttooltipEl.style.display = 'none';\n\t};\n\tdiamond.addEventListener('mouseenter', onTooltipEnter);\n\tdiamond.addEventListener('mousemove', onTooltipMove);\n\tdiamond.addEventListener('mouseleave', onTooltipLeave);\n\tconst cleanupTooltip = (): void => {\n\t\tdiamond.removeEventListener('mouseenter', onTooltipEnter);\n\t\tdiamond.removeEventListener('mousemove', onTooltipMove);\n\t\tdiamond.removeEventListener('mouseleave', onTooltipLeave);\n\t};\n\n\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag?: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t\tcleanupProgressDrag?: () => void;\n\t\tcleanupTooltip?: () => void;\n\t} = {bar: diamond, resizeHandle: dummy};\n\tif (cleanupDrag !== undefined) {\n\t\tentry.cleanupDrag = cleanupDrag;\n\t}\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\n\t}\n\tif (cleanupTooltip !== undefined) {\n\t\tentry.cleanupTooltip = cleanupTooltip;\n\t}\n\tregistry.set(task.id, entry);\n}\n\n/**\n * Full render of the right pane.\n * Grid lines and stripes are rebuilt each call (cheap — no event listeners).\n * Bars are rebuilt each call with fresh drag listeners (old ones cleaned up first).\n *\n * @param refs - The right pane DOM references.\n * @param state - The current chart state.\n * @param cbs - The chart callbacks.\n */\nexport function renderRightPane(refs: RightPaneRefs, state: GanttState, cbs: RightPaneCallbacks): void {\n\tconst {\n\t\tallRows,\n\t\tlayouts,\n\t\tlinks,\n\t\tmapper,\n\t\tscale,\n\t\tviewportStart,\n\t\tviewportEnd,\n\t\ttotalWidth,\n\t\tselectedId,\n\t\thighlightLinkedDependenciesOnSelect,\n\t\tpaddingTop,\n\t\tpaddingBottom,\n\t\tstartIndex,\n\t} = state;\n\n\tconst {stripeContainer, absoluteLayer, svgLayer, barRegistry} = refs;\n\tconst rowCount = allRows.length;\n\tconst contentHeight = totalContentHeight(rowCount);\n\n\t// ── Stripe rows (virtual slice only) ───────────────────────────────────\n\tconst visibleRows = allRows.slice(state.startIndex, state.endIndex + 1);\n\tclearChildren(stripeContainer);\n\tcss(stripeContainer, {width: `${totalWidth}px`});\n\n\t// Top spacer\n\tif (paddingTop > 0) {\n\t\tconst s = el('div');\n\t\ts.style.height = `${paddingTop}px`;\n\t\tstripeContainer.append(s);\n\t}\n\n\tfor (let i = 0; i < visibleRows.length; i++) {\n\t\tconst rowIdx = startIndex + i;\n\t\tconst stripe = el('div');\n\t\tcss(stripe, {\n\t\t\theight: `${ROW_HEIGHT}px`,\n\t\t\tbackground: rowIdx % 2 === 0 ? 'var(--gantt-bg)' : 'var(--gantt-stripe)',\n\t\t\tborderBottom: '1px solid var(--gantt-border)',\n\t\t});\n\t\tstripeContainer.append(stripe);\n\t}\n\n\t// Bottom spacer\n\tif (paddingBottom > 0) {\n\t\tconst s = el('div');\n\t\ts.style.height = `${paddingBottom}px`;\n\t\tstripeContainer.append(s);\n\t}\n\n\t// ── Absolute layer: grid lines + today + bars ──────────────────────────\n\tcss(absoluteLayer, {width: `${totalWidth}px`, height: `${contentHeight}px`});\n\n\t// Remove all children except svgLayer (last child)\n\tconst toRemove: Element[] = [];\n\tfor (const child of [...absoluteLayer.children]) {\n\t\tif (child !== svgLayer) {\n\t\t\ttoRemove.push(child);\n\t\t}\n\t}\n\tfor (const node of toRemove) {\n\t\tabsoluteLayer.removeChild(node);\n\t}\n\n\t// Clean up orphaned ghost line from interrupted drags\n\thideGhostLine(svgLayer);\n\n\t// Clean up previous drag listeners\n\tfor (const {cleanupDrag, cleanupLinkHandles, cleanupProgressDrag} of barRegistry.values()) {\n\t\tcleanupDrag?.();\n\t\tcleanupLinkHandles?.();\n\t\tcleanupProgressDrag?.();\n\t}\n\tbarRegistry.clear();\n\n\t// Special day backgrounds (day scale only)\n\tif (scale === 'day') {\n\t\trenderSpecialDayBackgrounds(absoluteLayer, svgLayer, state, contentHeight);\n\t}\n\n\t// Grid lines\n\tlet gridCur = snapToScaleBoundary(viewportStart, scale);\n\twhile (gridCur <= viewportEnd) {\n\t\tconst x = mapper.toX(gridCur);\n\t\tconst line = el('div');\n\t\tcss(line, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${x}px`,\n\t\t\ttop: '0',\n\t\t\twidth: '1px',\n\t\t\theight: `${contentHeight}px`,\n\t\t\tbackground: 'var(--gantt-grid-line)',\n\t\t\tpointerEvents: 'none',\n\t\t});\n\t\tabsoluteLayer.insertBefore(line, svgLayer);\n\t\tgridCur = nextScaleBoundary(gridCur, scale);\n\t}\n\n\t// Today marker (render only when enabled and within timeline bounds)\n\tconst todayX = mapper.toX(new Date());\n\tconst todayLineWidth = 2;\n\tif (state.showTodayMarker && todayX >= 0 && todayX <= totalWidth - todayLineWidth) {\n\t\tconst todayLine = el('div');\n\t\ttodayLine.className = 'gantt-today-marker';\n\t\tcss(todayLine, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${todayX}px`,\n\t\t\ttop: '0',\n\t\t\twidth: `${todayLineWidth}px`,\n\t\t\theight: `${contentHeight}px`,\n\t\t\tbackground: 'var(--gantt-today)',\n\t\t\tpointerEvents: 'none',\n\t\t\tzIndex: '5',\n\t\t});\n\t\tabsoluteLayer.insertBefore(todayLine, svgLayer);\n\t}\n\n\tconst visibleTaskIds = new Set(visibleRows.map((task) => task.id));\n\n\t// Bars (virtual slice only)\n\tfor (const task of visibleRows) {\n\t\tconst layout = layouts.get(task.id);\n\t\tif (layout === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (layout.kind === 'milestone') {\n\t\t\trenderMilestone(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, cbs, state, refs.tooltipEl);\n\t\t} else {\n\t\t\trenderBar(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, state, cbs, refs.tooltipEl);\n\t\t}\n\t}\n\n\t// SVG dependency overlay (visible rows only)\n\tconst visibleLinks = links.filter((link) => visibleTaskIds.has(link.sourceTaskId) && visibleTaskIds.has(link.targetTaskId));\n\tupdateDependencyLayer(svgLayer, visibleLinks, totalWidth, contentHeight, selectedId, highlightLinkedDependenciesOnSelect, cbs);\n}\n","import {SpecialDaySchema, type _GanttInputZod as GanttInput, type SpecialDay} from '../validation/schemas.ts';\nimport {parseDate} from '../domain/dateMath.ts';\nimport {buildTaskTree} from '../domain/tree.ts';\nimport {type ResolvedSpecialDay} from './state.ts';\n\nexport function buildTaskIndex(tasks: GanttInput['tasks']): Map<number, number> {\n\tconst index = new Map<number, number>();\n\tfor (let i = 0; i < tasks.length; i++) {\n\t\tconst task = tasks[i];\n\t\tif (task !== undefined) {\n\t\t\tindex.set(task.id, i);\n\t\t}\n\t}\n\treturn index;\n}\n\nexport function toIsoDate(date: Date): string {\n\treturn date.toISOString().slice(0, 10);\n}\n\nexport function buildSpecialDayIndex(specialDays: SpecialDay[]): Map<string, ResolvedSpecialDay> {\n\tconst map = new Map<string, ResolvedSpecialDay>();\n\tfor (const specialDay of specialDays) {\n\t\tconst parsed = SpecialDaySchema.parse(specialDay);\n\t\tconst isoDate = toIsoDate(parseDate(parsed.date));\n\t\tmap.set(isoDate, {\n\t\t\tkind: parsed.kind,\n\t\t\t...(parsed.label === undefined ? {} : {label: parsed.label}),\n\t\t\t...(parsed.className === undefined ? {} : {className: parsed.className}),\n\t\t});\n\t}\n\treturn map;\n}\n\nexport function normalizeWeekendDays(days: number[] | undefined): Set<number> {\n\tif (days === undefined) {\n\t\treturn new Set([0, 6]);\n\t}\n\n\tconst normalized = new Set<number>();\n\tfor (const day of days) {\n\t\tif (!Number.isInteger(day) || day < 0 || day > 6) {\n\t\t\tthrow new Error('weekendDays must contain integers in range 0..6');\n\t\t}\n\t\tnormalized.add(day);\n\t}\n\treturn normalized;\n}\n\nexport function getExpandableTaskIds(tasks: GanttInput['tasks']): Set<number> {\n\tconst roots = buildTaskTree(tasks);\n\tconst expandableIds = new Set<number>();\n\tconst stack = [...roots];\n\twhile (stack.length > 0) {\n\t\tconst node = stack.pop();\n\t\tif (node === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (node.children.length > 0) {\n\t\t\texpandableIds.add(node.id);\n\t\t}\n\t\tfor (const child of node.children) {\n\t\t\tstack.push(child);\n\t\t}\n\t}\n\treturn expandableIds;\n}\n\nexport function getInitialExpandedIds(tasks: GanttInput['tasks']): Set<number> {\n\tconst expandableIds = getExpandableTaskIds(tasks);\n\tconst expandedIds = new Set<number>();\n\tfor (const task of tasks) {\n\t\tif (task.kind === 'project' && task.open && expandableIds.has(task.id)) {\n\t\t\texpandedIds.add(task.id);\n\t\t}\n\t}\n\treturn expandedIds;\n}\n","const MIN_PANE_WIDTH = 96;\n\nexport function attachSplitter(\n\tsplitterHandle: HTMLElement,\n\tleftPane: HTMLElement,\n\tcontainer: HTMLElement,\n\ttimelineMinWidth: number,\n\tonDragEnd: (width: number) => void,\n): void {\n\tsplitterHandle.addEventListener('pointerdown', (e: PointerEvent) => {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tconst startX = e.clientX;\n\t\tconst startWidth = Number.parseFloat(leftPane.style.width) || 0;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tlet newWidth = startWidth + dx;\n\t\t\tconst hostWidth = container.clientWidth;\n\t\t\tif (hostWidth > 0) {\n\t\t\t\tnewWidth = Math.max(MIN_PANE_WIDTH, Math.min(newWidth, hostWidth - timelineMinWidth));\n\t\t\t}\n\t\t\tnewWidth = Math.max(MIN_PANE_WIDTH, newWidth);\n\t\t\tleftPane.style.width = `${newWidth}px`;\n\t\t\tleftPane.style.minWidth = `${newWidth}px`;\n\t\t\tleftPane.style.maxWidth = `${newWidth}px`;\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tconst finalWidth = Number.parseFloat(leftPane.style.width);\n\t\t\tonDragEnd(finalWidth);\n\t\t}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t});\n}\n","export const MOBILE_BREAKPOINT = 768;\nexport const MOBILE_LEFT_PANE_MIN_WIDTH = 140;\nexport const MOBILE_LEFT_PANE_MAX_RATIO = 0.45;\nexport const TIMELINE_MIN_WIDTH = 220;\nexport const DESKTOP_MIN_RATIO = 0.25;\nexport const DESKTOP_MAX_RATIO = 0.4;\nconst MIN_PANE_WIDTH = 96;\n\nexport type ComputeLeftPaneWidthOptions = {\n\thostWidth: number;\n\tdefaultWidth: number;\n\tuserSplitWidth: number | null;\n\texplicitOptWidth: number | undefined;\n\tresponsiveSplitPane: boolean;\n\tmobileBreakpoint: number;\n\tmobileLeftPaneMinWidth: number;\n\tmobileLeftPaneMaxRatio: number;\n\ttimelineMinWidth: number;\n};\n\nexport function computeLeftPaneWidth(options: ComputeLeftPaneWidthOptions): number {\n\tconst {\n\t\thostWidth,\n\t\tdefaultWidth,\n\t\tuserSplitWidth,\n\t\texplicitOptWidth,\n\t\tresponsiveSplitPane,\n\t\tmobileBreakpoint,\n\t\tmobileLeftPaneMinWidth,\n\t\tmobileLeftPaneMaxRatio,\n\t\ttimelineMinWidth,\n\t} = options;\n\n\tlet width = defaultWidth;\n\n\tif (hostWidth <= 0) {\n\t\treturn width;\n\t}\n\n\tif (userSplitWidth !== null) {\n\t\twidth = userSplitWidth;\n\t} else if (explicitOptWidth !== undefined) {\n\t\twidth = explicitOptWidth;\n\t} else if (responsiveSplitPane && hostWidth <= mobileBreakpoint) {\n\t\tconst ratioWidth = Math.floor(hostWidth * mobileLeftPaneMaxRatio);\n\t\twidth = Math.min(defaultWidth, Math.max(mobileLeftPaneMinWidth, ratioWidth));\n\t} else {\n\t\tconst minProportional = Math.floor(hostWidth * DESKTOP_MIN_RATIO);\n\t\tconst maxProportional = Math.floor(hostWidth * DESKTOP_MAX_RATIO);\n\t\twidth = Math.min(maxProportional, Math.max(defaultWidth, minProportional));\n\t}\n\n\tconst maxAllowed = Math.max(MIN_PANE_WIDTH, hostWidth - timelineMinWidth);\n\twidth = Math.min(width, maxAllowed);\n\n\treturn Math.max(MIN_PANE_WIDTH, Math.floor(width));\n}\n","import {\n\ttype _GanttInputZod,\n\ttype GanttInputRaw,\n\tGanttInputSchema,\n\ttype SpecialDay,\n\ttype ZodTaskInferred,\n\ttype Task as GenTask,\n\ttype Link as GenLink,\n} from '../validation/schemas.ts';\nimport {validateLinkRefs, detectCycles} from '../domain/dependencies.ts';\nimport {buildTaskTree, flattenTree} from '../domain/tree.ts';\nimport {createPixelMapper} from '../timeline/pixelMapper.ts';\nimport {computeLayout, deriveViewport, ROW_HEIGHT} from '../timeline/layoutEngine.ts';\nimport {routeLinks} from '../rendering/linkRouter.ts';\nimport {ceilToScaleBoundary, type TimeScale} from '../timeline/scale.ts';\nimport {type GanttState, type ResolvedSpecialDay} from './state.ts';\nimport {el, css, clearChildren} from './dom/helpers.ts';\nimport {renderTimeHeader} from './dom/timeHeader.ts';\nimport {renderLeftPane, buildLeftPaneHeader, setupColumnResize} from './dom/leftPane.ts';\nimport {createRightPaneRefs, renderRightPane} from './dom/rightPane.ts';\nimport {type RightPaneRefs} from './dom/rightPane.ts';\nimport {type GridColumn, gridNaturalWidth, gridColumnDefaults} from './dom/gridColumns.ts';\nimport {parseDate, diffHours} from '../domain/dateMath.ts';\nimport {GanttError} from '../errors.ts';\nimport {buildTaskIndex, buildSpecialDayIndex, normalizeWeekendDays, getExpandableTaskIds, getInitialExpandedIds} from './utils.ts';\nimport {attachSplitter} from './splitter.ts';\nimport {computeLeftPaneWidth, MOBILE_BREAKPOINT, MOBILE_LEFT_PANE_MIN_WIDTH, MOBILE_LEFT_PANE_MAX_RATIO, TIMELINE_MIN_WIDTH} from './responsive.ts';\nimport {type ChartLocale, resolveChartLocale} from '../locale.ts';\n\n/** Internal convenience aliases for the zod-inferred runtime types (include `data?: Record<string, unknown>`). */\ntype GanttInput = _GanttInputZod;\ntype Task = ZodTaskInferred;\n\nexport type OnTaskClick<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnTaskDoubleClick<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnTaskMove<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tnewStartDate: Date;\n\tnewEndDate: Date;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnTaskResize<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tnewDurationHours: number;\n\tnewStartDate: Date;\n\tnewEndDate: Date;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnTaskAdd<TTaskData = never, TLinkData = never> = (payload: {\n\tparentTask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnLinkCreate<TTaskData = never, TLinkData = never> = (payload: {\n\ttype: 'FS';\n\tsourceTask: GenTask<TTaskData>;\n\ttargetTask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnLinkClick<TTaskData = never, TLinkData = never> = (payload: {\n\tlink: GenLink<TLinkData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnLinkDblClick<TTaskData = never, TLinkData = never> = (payload: {\n\tlink: GenLink<TLinkData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnProgressChange<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tnewPercentComplete: number;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnExpandCollapse<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnExpandCollapseAll<TTaskData = never, TLinkData = never> = (payload: {\n\ttasks: GenTask<TTaskData>[];\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnTooltipText<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => string | null;\n\nexport type GanttCallbacks<TTaskData = never, TLinkData = never> = {\n\tonTaskClick?: OnTaskClick<TTaskData, TLinkData>;\n\tonTaskDoubleClick?: OnTaskDoubleClick<TTaskData, TLinkData>;\n\tonTaskMove?: OnTaskMove<TTaskData, TLinkData>;\n\tonTaskResize?: OnTaskResize<TTaskData, TLinkData>;\n\tonTaskAdd?: OnTaskAdd<TTaskData, TLinkData>;\n\tonLinkCreate?: OnLinkCreate<TTaskData, TLinkData>;\n\tonLinkClick?: OnLinkClick<TTaskData, TLinkData>;\n\tonLinkDblClick?: OnLinkDblClick<TTaskData, TLinkData>;\n\tonProgressChange?: OnProgressChange<TTaskData, TLinkData>;\n\tonExpandCollapse?: OnExpandCollapse<TTaskData, TLinkData>;\n\tonExpandCollapseAll?: OnExpandCollapseAll<TTaskData, TLinkData>;\n\tonTooltipText?: OnTooltipText<TTaskData, TLinkData>;\n\tonLeftPaneWidthChange?: (payload: {width: number; instance: GanttInstance<TTaskData, TLinkData>}) => void | Promise<void>;\n\tonGridColumnsChange?: (payload: {columns: GridColumn[]; instance: GanttInstance<TTaskData, TLinkData>}) => void | Promise<void>;\n};\n\ntype InternalCallbacks = {\n\tonTaskClick?: (id: number) => void;\n\tonTaskMove?: (payload: {id: number; startDate: Date}) => void;\n\t_onTaskMoveFinal?: (payload: {id: number; startDate: Date}) => Promise<boolean>;\n\tonTaskResize?: (payload: {id: number; endDate: string}) => void;\n\t_onTaskResizeFinal?: (payload: {id: number; endDate: string}) => Promise<boolean>;\n\tonTaskAdd?: (parentId: number) => void;\n\tonTaskEditIntent?: (payload: {id: number; source: 'grid' | 'bar' | 'milestone'; trigger: 'doubleClick'; task: Task}) => void;\n\tonTaskDoubleClick?: (payload: {id: number; task: Task}) => void;\n\tonLinkCreate?: (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n\tonLinkClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonLinkDblClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonTaskProgressDrag?: (payload: {id: number; percentComplete: number}) => void;\n\t_onTaskProgressDragFinal?: (payload: {id: number; percentComplete: number}) => Promise<boolean>;\n\tonTooltipText?: (payload: {id: number; task: Task}) => string | null;\n\tonLeftPaneWidthChange?: (width: number) => void;\n\tonGridColumnsChange?: (columns: GridColumn[]) => void;\n};\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\nexport type GanttOptions = {\n\tscale?: TimeScale;\n\thighlightLinkedDependenciesOnSelect?: boolean;\n\tlinkCreationEnabled?: boolean;\n\tprogressDragEnabled?: boolean;\n\tleftPaneWidth?: number;\n\tresponsiveSplitPane?: boolean;\n\tmobileBreakpoint?: number;\n\tmobileLeftPaneMinWidth?: number;\n\tmobileLeftPaneMaxRatio?: number;\n\ttimelineMinWidth?: number;\n\theight?: number;\n\tviewportStart?: Date;\n\tviewportEnd?: Date;\n\tlocale?: ChartLocale | string;\n\tshowWeekends?: boolean;\n\tweekendDays?: number[];\n\tspecialDays?: SpecialDay[];\n\tgridColumns?: GridColumn[];\n\ttheme?: ThemeMode;\n\tshowAddTaskButton?: boolean;\n\tshowTodayMarker?: boolean;\n};\n\nexport type GanttInstance<TTaskData = never, TLinkData = never> = {\n\tupdate: (input: GanttInputRaw<TTaskData, TLinkData>) => void;\n\tsetOptions: (opts: Partial<GanttOptions>) => void;\n\tsetCallbacks: (cbs: GanttCallbacks<TTaskData, TLinkData>) => void;\n\tselect: (id: number | null, fireCallback?: boolean) => void;\n\tcollapseAll: (fireCallback?: boolean) => void;\n\texpandAll: (fireCallback?: boolean) => void;\n\tgetOpenStates: () => {id: number; open: boolean}[];\n\tdestroy: () => void;\n};\n\nconst HEADER_H = 52;\nconst OVERSCAN = 4;\n\n/**\n * Progressive-enhancement Gantt chart component.\n * Validates input, builds a DOM tree, and renders a full interactive chart\n * inside the given container element.\n *\n * @param TTaskData - The type of the optional `data` property on tasks. Defaults to `never`.\n * @param TLinkData - The type of the optional `data` property on links. Defaults to `never`.\n *\n * @example\n * ```ts\n * const chart = new GanttChart(document.getElementById('chart')!, {\n * locale: 'de-DE',\n * theme: 'dark',\n * });\n * ```\n */\nexport class GanttChart<TTaskData = never, TLinkData = never> implements GanttInstance<TTaskData, TLinkData> {\n\treadonly #container: HTMLElement;\n\treadonly #opts: GanttOptions;\n\t#callbacks: GanttCallbacks<TTaskData, TLinkData>;\n\t#input: GanttInput | null = null;\n\t#scale: TimeScale;\n\t#selectedId: number | null = null;\n\t#scrollTop = 0;\n\t#rafPending = false;\n\t#rafId: number | null = null;\n\t#destroyed = false;\n\treadonly #dragOriginals = new Map<number, Task>();\n\t#taskIndex: Map<number, number>;\n\t#lastGridClick: {id: number; atMs: number} | null = null;\n\t#userSplitWidth: number | null = null;\n\n\t#height: number;\n\t#locale: ChartLocale;\n\t#timelineMinWidth: number;\n\t#columns: GridColumn[];\n\t#leftPaneDefaultWidth: number;\n\t#showAddTaskButton: boolean;\n\t#weekendDays: Set<number>;\n\t#specialDaysByDate: Map<string, ResolvedSpecialDay>;\n\t#expandedIds: Set<number>;\n\n\t// oxlint-disable typescript-eslint(prefer-readonly)\n\t#root!: HTMLElement;\n\t#scrollEl!: HTMLElement;\n\t#leftPane!: HTMLElement;\n\t#leftHeader!: HTMLElement;\n\t#leftBody!: HTMLElement;\n\t#rightPane!: HTMLElement;\n\t#rightHeader!: HTMLElement;\n\t#rightPaneRefs!: RightPaneRefs;\n\t#cbs: InternalCallbacks;\n\n\t#resizeObserver: ResizeObserver | null = null;\n\t#columnResizeCleanup!: () => void;\n\n\t/**\n\t * Constructs a new chart, builds the DOM, and wires internal event handling.\n\t * Data must be loaded via {@link update} before the chart renders.\n\t * Callbacks must be set via {@link setCallbacks} before user interactions are handled.\n\t *\n\t * @param container - The host `HTMLElement` the chart will be appended to.\n\t * @param opts - Configuration options.\n\t */\n\tpublic constructor(container: HTMLElement, opts: GanttOptions = {}) {\n\t\tthis.#container = container;\n\n\t\tthis.#scale = opts.scale ?? 'day';\n\t\tthis.#opts = opts;\n\t\tthis.#callbacks = {};\n\t\tthis.#taskIndex = new Map();\n\t\tthis.#locale = resolveChartLocale(opts.locale);\n\t\tthis.#columns = opts.gridColumns ?? gridColumnDefaults(this.#locale);\n\t\tthis.#showAddTaskButton = opts.showAddTaskButton ?? true;\n\t\tthis.#syncActionsColumnVisibility();\n\t\tthis.#leftPaneDefaultWidth = opts.leftPaneWidth ?? gridNaturalWidth(this.#columns);\n\t\tthis.#height = opts.height ?? 500;\n\t\tthis.#timelineMinWidth = opts.timelineMinWidth ?? TIMELINE_MIN_WIDTH;\n\t\tthis.#weekendDays = normalizeWeekendDays(opts.weekendDays ?? this.#locale.weekendDays);\n\t\tthis.#specialDaysByDate = buildSpecialDayIndex(opts.specialDays ?? []);\n\t\tthis.#expandedIds = new Set();\n\n\t\tthis.#cbs = this.#buildCallbackAdapter();\n\n\t\tthis.#buildDom();\n\t\tthis.#wireEvents();\n\n\t\tcontainer.append(this.#root);\n\n\t\tthis.#applyTheme();\n\n\t\tthis.#applyResponsivePaneStyles();\n\t\tthis.#setupResizeObserver();\n\t}\n\n\t#buildCallbackAdapter(this: GanttChart<TTaskData, TLinkData>): InternalCallbacks {\n\t\treturn {\n\t\t\tonTaskClick: (id): void => {\n\t\t\t\tif (this.#selectedId === id) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.#selectedId = id;\n\t\t\t\tif (this.#selectedId !== null) {\n\t\t\t\t\tconst task = this.#findTask(this.#selectedId);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tvoid this.#callbacks.onTaskClick?.({task: task as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonTaskDoubleClick: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onTaskDoubleClick?.({task: payload.task as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t},\n\t\t\tonTaskEditIntent: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onTaskDoubleClick?.({task: payload.task as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t},\n\t\t\tonTaskMove: (payload): void => {\n\t\t\t\tif (!this.#dragOriginals.has(payload.id)) {\n\t\t\t\t\tconst task = this.#input?.tasks.find((t) => t.id === payload.id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tthis.#dragOriginals.set(payload.id, task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst iso = payload.startDate.toISOString().slice(0, 10);\n\t\t\t\tthis.#patchTask(payload.id, {startDate: iso});\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\t_onTaskMoveFinal: async (payload): Promise<boolean> => {\n\t\t\t\tconst task = this.#findTask(payload.id);\n\t\t\t\tif (task !== undefined) {\n\t\t\t\t\tconst newEndDate = task.kind !== 'milestone' ? parseDate(task.endDate) : payload.startDate;\n\t\t\t\t\tconst result = this.#callbacks.onTaskMove?.({\n\t\t\t\t\t\ttask: task as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tnewStartDate: payload.startDate,\n\t\t\t\t\t\tnewEndDate,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t\tif (!(await result)) {\n\t\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\t\tif (original !== undefined) {\n\t\t\t\t\t\t\t\tthis.#patchTask(payload.id, {startDate: original.startDate});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!result) {\n\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\tif (original !== undefined) {\n\t\t\t\t\t\t\tthis.#patchTask(payload.id, {startDate: original.startDate});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#dragOriginals.clear();\n\t\t\t\tthis.#scheduleRender();\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tonTaskResize: (payload): void => {\n\t\t\t\tif (!this.#dragOriginals.has(payload.id)) {\n\t\t\t\t\tconst task = this.#input?.tasks.find((t) => t.id === payload.id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tthis.#dragOriginals.set(payload.id, task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#patchTask(payload.id, {endDate: payload.endDate});\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\t_onTaskResizeFinal: async (payload): Promise<boolean> => {\n\t\t\t\tconst task = this.#findTask(payload.id);\n\t\t\t\tif (task !== undefined && task.kind !== 'milestone') {\n\t\t\t\t\tconst newStartDate = parseDate(task.startDate);\n\t\t\t\t\tconst newEndDate = parseDate(task.endDate);\n\t\t\t\t\tconst newDurationHours = diffHours(newEndDate, newStartDate);\n\t\t\t\t\tconst result = this.#callbacks.onTaskResize?.({\n\t\t\t\t\t\ttask: task as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tnewDurationHours,\n\t\t\t\t\t\tnewStartDate,\n\t\t\t\t\t\tnewEndDate,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t\tif (!(await result)) {\n\t\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\t\tthis.#patchTask(payload.id, {endDate: original.endDate});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!result) {\n\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\tthis.#patchTask(payload.id, {endDate: original.endDate});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#dragOriginals.clear();\n\t\t\t\tthis.#scheduleRender();\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tonTaskProgressDrag: (payload): void => {\n\t\t\t\tif (!this.#dragOriginals.has(payload.id)) {\n\t\t\t\t\tconst task = this.#input?.tasks.find((t) => t.id === payload.id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tthis.#dragOriginals.set(payload.id, task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#patchTask(payload.id, {percentComplete: payload.percentComplete});\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\t_onTaskProgressDragFinal: async (payload): Promise<boolean> => {\n\t\t\t\tconst task = this.#findTask(payload.id);\n\t\t\t\tif (task !== undefined) {\n\t\t\t\t\tconst result = this.#callbacks.onProgressChange?.({\n\t\t\t\t\t\ttask: task as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tnewPercentComplete: payload.percentComplete,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t\tif (!(await result)) {\n\t\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\t\tthis.#patchTask(payload.id, {percentComplete: original.percentComplete});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!result) {\n\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\tthis.#patchTask(payload.id, {percentComplete: original.percentComplete});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#dragOriginals.clear();\n\t\t\t\tthis.#scheduleRender();\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tonTaskAdd: (parentId): void => {\n\t\t\t\tconst parentTask = this.#findTask(parentId);\n\t\t\t\tif (parentTask !== undefined) {\n\t\t\t\t\tvoid this.#callbacks.onTaskAdd?.({parentTask: parentTask as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t\t}\n\t\t\t},\n\t\t\tonLeftPaneWidthChange: (width): void => {\n\t\t\t\tvoid this.#callbacks.onLeftPaneWidthChange?.({width, instance: this});\n\t\t\t},\n\t\t\tonGridColumnsChange: (updatedColumns): void => {\n\t\t\t\tvoid this.#callbacks.onGridColumnsChange?.({columns: updatedColumns, instance: this});\n\t\t\t},\n\t\t\tonLinkCreate: (payload): void => {\n\t\t\t\tconst sourceTask = this.#findTask(payload.sourceTaskId);\n\t\t\t\tconst targetTask = this.#findTask(payload.targetTaskId);\n\t\t\t\tif (sourceTask !== undefined && targetTask !== undefined) {\n\t\t\t\t\tvoid this.#callbacks.onLinkCreate?.({\n\t\t\t\t\t\ttype: 'FS',\n\t\t\t\t\t\tsourceTask: sourceTask as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\ttargetTask: targetTask as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\tonLinkClick: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onLinkClick?.({link: payload as unknown as GenLink<TLinkData>, instance: this});\n\t\t\t},\n\t\t\tonLinkDblClick: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onLinkDblClick?.({link: payload as unknown as GenLink<TLinkData>, instance: this});\n\t\t\t},\n\t\t\tonTooltipText: (payload): string | null => this.#callbacks.onTooltipText?.({task: payload.task as unknown as GenTask<TTaskData>, instance: this}) ?? null,\n\t\t};\n\t}\n\n\t/**\n\t * Sets or replaces the chart's user-facing callbacks.\n\t * Does not trigger a re-render.\n\t *\n\t * @param cbs - The {@link GanttCallbacks} to register.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic setCallbacks(cbs: GanttCallbacks<TTaskData, TLinkData>): void {\n\t\tthis.#assertAlive();\n\t\tthis.#callbacks = cbs;\n\t\tthis.#cbs = this.#buildCallbackAdapter();\n\t}\n\n\t/**\n\t * Replaces the full dataset and re-renders.\n\t *\n\t * @param newInput - The new {@link GanttInput} to apply.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic update(newInput: GanttInputRaw<TTaskData, TLinkData>): void {\n\t\tthis.#assertAlive();\n\t\tconst input = GanttInputSchema.parse(newInput) as unknown as GanttInput;\n\t\tvalidateLinkRefs(input.tasks, input.links);\n\t\tdetectCycles(input.tasks, input.links);\n\t\tthis.#input = structuredClone(input);\n\t\tthis.#taskIndex = buildTaskIndex(this.#input.tasks);\n\t\tthis.#expandedIds = getInitialExpandedIds(this.#input.tasks);\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t}\n\n\t/**\n\t * Merges the supplied options into the current configuration and re-renders\n\t * only the panes affected by the changed options.\n\t *\n\t * @param opts - A partial {@link GanttOptions} object. Only the keys present\n\t * in this parameter are updated; missing keys keep their\n\t * previous values.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic setOptions(opts: Partial<GanttOptions>): void {\n\t\tthis.#assertAlive();\n\n\t\tObject.assign(this.#opts, opts);\n\n\t\tthis.#scale = this.#opts.scale ?? 'day';\n\n\t\tlet columnsChanged = false;\n\n\t\tif (opts.locale !== undefined) {\n\t\t\tthis.#locale = resolveChartLocale(opts.locale);\n\t\t\tif (this.#opts.gridColumns === undefined) {\n\t\t\t\tthis.#columns = gridColumnDefaults(this.#locale);\n\t\t\t\tthis.#leftPaneDefaultWidth = gridNaturalWidth(this.#columns);\n\t\t\t\tcolumnsChanged = true;\n\t\t\t}\n\t\t\tif (this.#opts.weekendDays === undefined) {\n\t\t\t\tthis.#weekendDays = normalizeWeekendDays(this.#locale.weekendDays);\n\t\t\t}\n\t\t}\n\n\t\tif (opts.gridColumns !== undefined) {\n\t\t\tthis.#columns = opts.gridColumns;\n\t\t\tthis.#leftPaneDefaultWidth = this.#opts.leftPaneWidth ?? gridNaturalWidth(this.#columns);\n\t\t\tcolumnsChanged = true;\n\t\t}\n\n\t\tif (columnsChanged && this.#input !== null) {\n\t\t\tthis.#rebuildLeftPaneHeader();\n\t\t}\n\n\t\tif (opts.leftPaneWidth !== undefined) {\n\t\t\tthis.#leftPaneDefaultWidth = opts.leftPaneWidth;\n\t\t}\n\n\t\tif (opts.height !== undefined) {\n\t\t\tthis.#height = opts.height;\n\t\t\tthis.#root.style.height = `${this.#height}px`;\n\t\t}\n\n\t\tif (opts.timelineMinWidth !== undefined) {\n\t\t\tthis.#timelineMinWidth = opts.timelineMinWidth;\n\t\t\tthis.#rightPane.style.minWidth = `${this.#timelineMinWidth}px`;\n\t\t}\n\n\t\tif (opts.weekendDays !== undefined) {\n\t\t\tthis.#weekendDays = normalizeWeekendDays(opts.weekendDays);\n\t\t}\n\n\t\tif (opts.specialDays !== undefined) {\n\t\t\tthis.#specialDaysByDate = buildSpecialDayIndex(opts.specialDays);\n\t\t}\n\n\t\tif (opts.theme !== undefined) {\n\t\t\tthis.#applyTheme();\n\t\t}\n\n\t\tif (opts.showAddTaskButton !== undefined) {\n\t\t\tthis.#showAddTaskButton = opts.showAddTaskButton;\n\t\t\tthis.#syncActionsColumnVisibility();\n\t\t\tconst naturalWidth = gridNaturalWidth(this.#columns);\n\t\t\tif (naturalWidth !== this.#leftPaneDefaultWidth) {\n\t\t\t\tthis.#leftPaneDefaultWidth = naturalWidth;\n\t\t\t\tcolumnsChanged = true;\n\t\t\t\tthis.#rebuildLeftPaneHeader();\n\t\t\t}\n\t\t}\n\n\t\tconst hasLayoutChange =\n\t\t\topts.leftPaneWidth !== undefined ||\n\t\t\topts.responsiveSplitPane !== undefined ||\n\t\t\topts.mobileBreakpoint !== undefined ||\n\t\t\topts.mobileLeftPaneMinWidth !== undefined ||\n\t\t\topts.mobileLeftPaneMaxRatio !== undefined ||\n\t\t\topts.timelineMinWidth !== undefined;\n\n\t\tif (hasLayoutChange) {\n\t\t\tthis.#applyResponsivePaneStyles();\n\t\t}\n\n\t\tconst hasLeftPaneChange = columnsChanged || opts.locale !== undefined || opts.showAddTaskButton !== undefined;\n\n\t\tconst hasRightPaneChange =\n\t\t\topts.scale !== undefined ||\n\t\t\topts.showTodayMarker !== undefined ||\n\t\t\topts.showWeekends !== undefined ||\n\t\t\topts.weekendDays !== undefined ||\n\t\t\topts.specialDays !== undefined ||\n\t\t\topts.highlightLinkedDependenciesOnSelect !== undefined ||\n\t\t\topts.linkCreationEnabled !== undefined ||\n\t\t\topts.progressDragEnabled !== undefined ||\n\t\t\topts.viewportStart !== undefined ||\n\t\t\topts.viewportEnd !== undefined ||\n\t\t\topts.locale !== undefined ||\n\t\t\topts.timelineMinWidth !== undefined;\n\n\t\tconst hasVisualChange = hasLeftPaneChange || hasRightPaneChange || hasLayoutChange;\n\n\t\tif (!hasVisualChange) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\n\t\tif (hasLeftPaneChange && !hasRightPaneChange) {\n\t\t\tthis.#renderGrid();\n\t\t} else if (!hasLeftPaneChange && hasRightPaneChange) {\n\t\t\tthis.#renderTimeline();\n\t\t} else {\n\t\t\tthis.#render();\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically selects or deselects a task.\n\t *\n\t * @param id - The task ID to select, or `null` to clear the selection.\n\t * @param fireCallback - Whether to fire the `onTaskClick` callback. Default `false`.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic select(id: number | null, fireCallback = false): void {\n\t\tthis.#assertAlive();\n\t\tif (id === null) {\n\t\t\tthis.#selectedId = null;\n\t\t} else {\n\t\t\tconst task = this.#input?.tasks.find((t) => t.id === id);\n\t\t\tif (task !== undefined && fireCallback) {\n\t\t\t\tvoid this.#callbacks.onTaskClick?.({task, instance: this});\n\t\t\t}\n\t\t\tthis.#selectedId = id;\n\t\t}\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t}\n\n\t/**\n\t * Collapses all expandable groups in the task tree.\n\t *\n\t * @param fireCallback - Whether to fire the `onExpandCollapseAll` callback. Default `false`.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic collapseAll(fireCallback = false): void {\n\t\tthis.#assertAlive();\n\t\tconst changed = fireCallback ? this.#buildExpandCollapseAllPayload(false) : [];\n\t\tthis.#expandedIds.clear();\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t\tif (changed.length > 0) {\n\t\t\tvoid this.#callbacks.onExpandCollapseAll?.({tasks: changed as unknown as GenTask<TTaskData>[], instance: this});\n\t\t}\n\t}\n\n\t/**\n\t * Expands all expandable groups in the task tree.\n\t *\n\t * @param fireCallback - Whether to fire the `onExpandCollapseAll` callback. Default `false`.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic expandAll(fireCallback = false): void {\n\t\tthis.#assertAlive();\n\t\tconst changed = fireCallback ? this.#buildExpandCollapseAllPayload(true) : [];\n\t\tthis.#expandedIds.clear();\n\t\tif (this.#input !== null) {\n\t\t\tfor (const id of getExpandableTaskIds(this.#input.tasks)) {\n\t\t\t\tthis.#expandedIds.add(id);\n\t\t\t}\n\t\t}\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t\tif (changed.length > 0) {\n\t\t\tvoid this.#callbacks.onExpandCollapseAll?.({tasks: changed as unknown as GenTask<TTaskData>[], instance: this});\n\t\t}\n\t}\n\n\t#buildExpandCollapseAllPayload(open: boolean): Task[] {\n\t\tif (this.#input === null) {\n\t\t\treturn [];\n\t\t}\n\t\tconst expandableIds = getExpandableTaskIds(this.#input.tasks);\n\t\tconst changed: Task[] = [];\n\t\tfor (const id of expandableIds) {\n\t\t\tconst currentlyExpanded = this.#expandedIds.has(id);\n\t\t\tif (currentlyExpanded !== open) {\n\t\t\t\tconst task = this.#findTask(id);\n\t\t\t\tif (task !== undefined) {\n\t\t\t\t\tchanged.push(task.kind === 'project' ? {...task, open} : {...task});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn changed;\n\t}\n\n\t/**\n\t * Returns the current expand/collapse state of every expandable node\n\t * (project tasks that have children). The result is ordered by the\n\t * input task list order.\n\t *\n\t * @returns An array of `{id, open}` objects for expandable nodes only.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic getOpenStates(): {id: number; open: boolean}[] {\n\t\tthis.#assertAlive();\n\t\tif (this.#input === null) {\n\t\t\treturn [];\n\t\t}\n\t\tconst expandableIds = getExpandableTaskIds(this.#input.tasks);\n\t\tconst result: {id: number; open: boolean}[] = [];\n\t\tfor (const task of this.#input.tasks) {\n\t\t\tif (expandableIds.has(task.id)) {\n\t\t\t\tresult.push({id: task.id, open: this.#expandedIds.has(task.id)});\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes the chart DOM and internal listeners, rendering the instance\n\t * unusable. Subsequent calls to any public method will throw.\n\t */\n\tpublic destroy(): void {\n\t\tif (this.#destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#destroyed = true;\n\t\tthis.#scrollEl.removeEventListener('scroll', this.#onScroll);\n\t\tif (this.#resizeObserver !== null) {\n\t\t\tthis.#resizeObserver.disconnect();\n\t\t} else {\n\t\t\twindow.removeEventListener('resize', this.#applyResponsivePaneStyles);\n\t\t}\n\t\tif (this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t}\n\t\tthis.#columnResizeCleanup();\n\t\tfor (const {cleanupDrag, cleanupLinkHandles, cleanupProgressDrag, cleanupTooltip} of this.#rightPaneRefs.barRegistry.values()) {\n\t\t\tcleanupDrag?.();\n\t\t\tcleanupLinkHandles?.();\n\t\t\tcleanupProgressDrag?.();\n\t\t\tcleanupTooltip?.();\n\t\t}\n\t\tclearChildren(this.#container);\n\t}\n\n\t#patchTask(id: number, patch: Partial<GanttInput['tasks'][number]>): void {\n\t\tif (this.#input === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst index = this.#taskIndex.get(id);\n\t\tif (index === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst target = this.#input.tasks[index];\n\t\tif (target === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#input.tasks[index] = {...target, ...patch} as Task;\n\t}\n\n\t#findTask(id: number): Task | undefined {\n\t\treturn this.#input?.tasks.find((t) => t.id === id);\n\t}\n\n\t#syncActionsColumnVisibility(): void {\n\t\tconst actionsCol = this.#columns.find((c) => c.id === 'actions');\n\t\tif (actionsCol !== undefined) {\n\t\t\tif (this.#showAddTaskButton) {\n\t\t\t\tdelete actionsCol.visible;\n\t\t\t} else {\n\t\t\t\tactionsCol.visible = false;\n\t\t\t}\n\t\t}\n\t}\n\n\treadonly #handleGridClick = (payload: {id: number; task: Task}): void => {\n\t\tconst now = Date.now();\n\t\tconst prev = this.#lastGridClick;\n\t\tif (prev !== null && prev.id === payload.id && now - prev.atMs <= 350) {\n\t\t\tthis.#lastGridClick = null;\n\t\t\tthis.#cbs.onTaskDoubleClick?.({id: payload.id, task: payload.task});\n\t\t\treturn;\n\t\t}\n\t\tthis.#lastGridClick = {id: payload.id, atMs: now};\n\t\tthis.#cbs.onTaskClick?.(payload.id);\n\t};\n\n\treadonly #onScroll = (): void => {\n\t\t({scrollTop: this.#scrollTop} = this.#scrollEl);\n\t\tthis.#scheduleRender();\n\t};\n\n\treadonly #applyResponsivePaneStyles = (): void => {\n\t\tconst computedWidth = computeLeftPaneWidth({\n\t\t\thostWidth: Math.max(0, this.#container.clientWidth),\n\t\t\tdefaultWidth: this.#leftPaneDefaultWidth,\n\t\t\tuserSplitWidth: this.#userSplitWidth,\n\t\t\texplicitOptWidth: this.#opts.leftPaneWidth,\n\t\t\tresponsiveSplitPane: this.#opts.responsiveSplitPane ?? true,\n\t\t\tmobileBreakpoint: this.#opts.mobileBreakpoint ?? MOBILE_BREAKPOINT,\n\t\t\tmobileLeftPaneMinWidth: this.#opts.mobileLeftPaneMinWidth ?? MOBILE_LEFT_PANE_MIN_WIDTH,\n\t\t\tmobileLeftPaneMaxRatio: this.#opts.mobileLeftPaneMaxRatio ?? MOBILE_LEFT_PANE_MAX_RATIO,\n\t\t\ttimelineMinWidth: this.#timelineMinWidth,\n\t\t});\n\t\tthis.#leftPane.style.width = `${computedWidth}px`;\n\t\tthis.#leftPane.style.minWidth = `${computedWidth}px`;\n\t\tthis.#leftPane.style.maxWidth = `${computedWidth}px`;\n\t\tthis.#rightPane.style.minWidth = `${this.#timelineMinWidth}px`;\n\t};\n\n\t#computeState(input: GanttInput): GanttState {\n\t\tconst roots = buildTaskTree(input.tasks);\n\t\tconst allRows = flattenTree(roots, this.#expandedIds);\n\t\tconst [vpStart, vpEnd] =\n\t\t\tthis.#opts.viewportStart !== undefined && this.#opts.viewportEnd !== undefined\n\t\t\t\t? [this.#opts.viewportStart, this.#opts.viewportEnd]\n\t\t\t\t: deriveViewport(allRows, 48);\n\t\tconst weekStartsOn = this.#locale.weekStartsOn ?? 1;\n\t\tconst renderViewportEnd = ceilToScaleBoundary(vpEnd, this.#scale, weekStartsOn);\n\n\t\tconst mapper = createPixelMapper(this.#scale, vpStart);\n\t\tconst totalWidth = Math.ceil(mapper.toX(renderViewportEnd)) + 1;\n\t\tconst layouts = computeLayout(allRows, mapper);\n\t\tconst links = routeLinks(input.links, layouts);\n\n\t\tconst containerH = this.#height - HEADER_H;\n\t\tconst rowCount = allRows.length;\n\t\tconst startIndex = Math.max(0, Math.floor(this.#scrollTop / ROW_HEIGHT) - OVERSCAN);\n\t\tconst endIndex = Math.min(rowCount - 1, Math.ceil((this.#scrollTop + containerH) / ROW_HEIGHT) + OVERSCAN - 1);\n\t\tconst paddingTop = startIndex * ROW_HEIGHT;\n\t\tconst paddingBottom = Math.max(0, (rowCount - 1 - endIndex) * ROW_HEIGHT);\n\n\t\treturn {\n\t\t\tinput,\n\t\t\tscale: this.#scale,\n\t\t\thighlightLinkedDependenciesOnSelect: this.#opts.highlightLinkedDependenciesOnSelect ?? false,\n\t\t\tlinkCreationEnabled: this.#opts.linkCreationEnabled ?? false,\n\t\t\tprogressDragEnabled: this.#opts.progressDragEnabled ?? false,\n\t\t\texpandedIds: this.#expandedIds,\n\t\t\tselectedId: this.#selectedId,\n\t\t\tscrollTop: this.#scrollTop,\n\t\t\tallRows,\n\t\t\tmapper,\n\t\t\tviewportStart: vpStart,\n\t\t\tviewportEnd: renderViewportEnd,\n\t\t\ttotalWidth,\n\t\t\tlayouts,\n\t\t\tlinks,\n\t\t\tstartIndex,\n\t\t\tendIndex,\n\t\t\tpaddingTop,\n\t\t\tpaddingBottom,\n\t\t\tshowWeekends: this.#opts.showWeekends ?? true,\n\t\t\tshowTodayMarker: this.#opts.showTodayMarker ?? true,\n\t\t\tweekendDays: this.#weekendDays,\n\t\t\tspecialDaysByDate: this.#specialDaysByDate,\n\t\t\tlocale: this.#locale,\n\t\t};\n\t}\n\n\treadonly #render = (): void => {\n\t\tthis.#rafPending = false;\n\t\tconst input = this.#input;\n\t\tif (input === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst state = this.#computeState(input);\n\n\t\trenderTimeHeader(this.#rightHeader, state);\n\t\tthis.#renderGridInternal(state);\n\t\trenderRightPane(this.#rightPaneRefs, state, this.#cbs);\n\t};\n\n\treadonly #renderGrid = (): void => {\n\t\tthis.#rafPending = false;\n\t\tconst input = this.#input;\n\t\tif (input === null) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#renderGridInternal(this.#computeState(input));\n\t};\n\n\t#renderGridInternal(state: GanttState): void {\n\t\trenderLeftPane(\n\t\t\tthis.#leftBody,\n\t\t\tstate,\n\t\t\t{\n\t\t\t\tonToggle: (id) => {\n\t\t\t\t\tconst expanded = !this.#expandedIds.has(id);\n\t\t\t\t\tif (expanded) {\n\t\t\t\t\t\tthis.#expandedIds.add(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#expandedIds.delete(id);\n\t\t\t\t\t}\n\t\t\t\t\tconst task = this.#findTask(id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tconst payload = task.kind === 'project' ? {...task, open: expanded} : {...task};\n\t\t\t\t\t\tvoid this.#callbacks.onExpandCollapse?.({\n\t\t\t\t\t\t\ttask: payload as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthis.#scheduleRender();\n\t\t\t\t},\n\t\t\t\tonTaskClick: (id) => this.#cbs.onTaskClick?.(id),\n\t\t\t\tonRowClick: (payload) => {\n\t\t\t\t\tthis.#handleGridClick(payload);\n\t\t\t\t},\n\t\t\t\tonTaskDoubleClick: (payload) => this.#cbs.onTaskDoubleClick?.(payload),\n\t\t\t\tonTaskAdd: (id) => this.#cbs.onTaskAdd?.(id),\n\t\t\t},\n\t\t\tthis.#columns,\n\t\t\tthis.#showAddTaskButton,\n\t\t);\n\t}\n\n\treadonly #renderTimeline = (): void => {\n\t\tthis.#rafPending = false;\n\t\tconst input = this.#input;\n\t\tif (input === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst state = this.#computeState(input);\n\n\t\trenderTimeHeader(this.#rightHeader, state);\n\t\trenderRightPane(this.#rightPaneRefs, state, this.#cbs);\n\t};\n\n\t#rebuildLeftPaneHeader(): void {\n\t\tthis.#columnResizeCleanup();\n\t\tclearChildren(this.#leftHeader);\n\t\tconst headerEl = buildLeftPaneHeader(this.#columns, this.#locale);\n\t\tthis.#wireHeaderTreeControls(headerEl);\n\t\tthis.#leftHeader.append(headerEl);\n\t\tthis.#columnResizeCleanup = setupColumnResize(headerEl, this.#leftBody, this.#columns, (updated) => {\n\t\t\tthis.#cbs.onGridColumnsChange?.(updated);\n\t\t});\n\t}\n\n\t#wireHeaderTreeControls(headerEl: HTMLElement): void {\n\t\tconst expandBtn = headerEl.querySelector<HTMLElement>('.gantt-header-expand-btn');\n\t\tconst collapseBtn = headerEl.querySelector<HTMLElement>('.gantt-header-collapse-btn');\n\t\tif (expandBtn !== null) {\n\t\t\texpandBtn.addEventListener('click', (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.expandAll(true);\n\t\t\t});\n\t\t}\n\t\tif (collapseBtn !== null) {\n\t\t\tcollapseBtn.addEventListener('click', (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.collapseAll(true);\n\t\t\t});\n\t\t}\n\t}\n\n\t#scheduleRender(): void {\n\t\tif (this.#rafPending || this.#destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#rafPending = true;\n\t\tthis.#rafId = requestAnimationFrame(this.#render);\n\t}\n\n\t#applyTheme(): void {\n\t\tconst theme = this.#opts.theme ?? 'system';\n\t\tthis.#container.dataset['theme'] = theme;\n\t}\n\n\t#assertAlive(): void {\n\t\tif (this.#destroyed) {\n\t\t\tthrow new GanttError('INSTANCE_DESTROYED', 'Gantt instance was destroyed');\n\t\t}\n\t}\n\n\t#buildDom(): void {\n\t\tconst root = el('div');\n\t\troot.className = 'gantt-root';\n\t\tcss(root, {\n\t\t\theight: `${this.#height}px`,\n\t\t\toverflow: 'hidden',\n\t\t\tdisplay: 'flex',\n\t\t\tflexDirection: 'column',\n\t\t\tfontFamily: 'var(--gantt-font)',\n\t\t\tbackground: 'var(--gantt-bg)',\n\t\t});\n\t\tthis.#root = root;\n\n\t\tconst scrollEl = el('div');\n\t\tcss(scrollEl, {flex: '1', overflow: 'auto', position: 'relative', display: 'flex'});\n\t\troot.append(scrollEl);\n\t\tthis.#scrollEl = scrollEl;\n\n\t\tconst leftPane = el('div');\n\t\tleftPane.dataset['pane'] = 'left';\n\t\tcss(leftPane, {\n\t\t\twidth: `${this.#leftPaneDefaultWidth}px`,\n\t\t\tflexShrink: '0',\n\t\t\tposition: 'sticky',\n\t\t\tleft: '0',\n\t\t\tzIndex: '10',\n\t\t\tbackground: 'var(--gantt-bg)',\n\t\t\tborderRight: '1px solid var(--gantt-border)',\n\t\t});\n\t\tthis.#leftPane = leftPane;\n\n\t\tconst leftHeader = el('div');\n\t\tcss(leftHeader, {position: 'sticky', top: '0', zIndex: '11', background: 'var(--gantt-header-bg)'});\n\t\tconst headerEl = buildLeftPaneHeader(this.#columns, this.#locale);\n\t\tthis.#wireHeaderTreeControls(headerEl);\n\t\tleftHeader.append(headerEl);\n\t\tleftPane.append(leftHeader);\n\t\tthis.#leftHeader = leftHeader;\n\n\t\tconst leftBody = el('div');\n\t\tleftPane.append(leftBody);\n\t\tthis.#leftBody = leftBody;\n\n\t\tthis.#columnResizeCleanup = setupColumnResize(headerEl, leftBody, this.#columns, (updated) => {\n\t\t\tthis.#cbs.onGridColumnsChange?.(updated);\n\t\t});\n\n\t\tscrollEl.append(leftPane);\n\n\t\tconst rightPane = el('div');\n\t\trightPane.dataset['pane'] = 'right';\n\t\tcss(rightPane, {flexShrink: '0', position: 'relative', minWidth: `${this.#timelineMinWidth}px`});\n\t\tthis.#rightPane = rightPane;\n\n\t\tconst rightHeader = el('div');\n\t\tcss(rightHeader, {position: 'sticky', top: '0', zIndex: '9', background: 'var(--gantt-header-bg)'});\n\t\trightPane.append(rightHeader);\n\t\tthis.#rightHeader = rightHeader;\n\n\t\tthis.#rightPaneRefs = createRightPaneRefs();\n\t\trightPane.append(this.#rightPaneRefs.scrollContainer);\n\t\tscrollEl.append(rightPane);\n\n\t\tconst splitterHandle = el('div');\n\t\tsplitterHandle.className = 'gantt-splitter-handle';\n\t\tcss(splitterHandle, {\n\t\t\tposition: 'absolute',\n\t\t\tright: '0',\n\t\t\ttop: '0',\n\t\t\tbottom: '0',\n\t\t\twidth: '4px',\n\t\t\tcursor: 'col-resize',\n\t\t\tzIndex: '20',\n\t\t});\n\t\tleftPane.append(splitterHandle);\n\n\t\tattachSplitter(splitterHandle, leftPane, this.#container, this.#timelineMinWidth, (finalWidth) => {\n\t\t\tthis.#userSplitWidth = finalWidth;\n\t\t\tthis.#cbs.onLeftPaneWidthChange?.(finalWidth);\n\t\t});\n\t}\n\n\t#wireEvents(): void {\n\t\tthis.#rightPaneRefs.absoluteLayer.addEventListener('click', (event) => {\n\t\t\tconst target = event.target as HTMLElement;\n\t\t\tif (target.closest('.gantt-bar, .gantt-milestone, .gantt-resize-handle')) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#selectedId = null;\n\t\t\tthis.#scheduleRender();\n\t\t});\n\n\t\tthis.#root.addEventListener('keydown', (event) => {\n\t\t\tif (event.key === 'Escape' && this.#selectedId !== null) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#selectedId = null;\n\t\t\t\tthis.#scheduleRender();\n\t\t\t}\n\t\t});\n\n\t\tthis.#scrollEl.addEventListener('scroll', this.#onScroll);\n\t}\n\n\t#setupResizeObserver(): void {\n\t\tif (typeof ResizeObserver !== 'undefined') {\n\t\t\tthis.#resizeObserver = new ResizeObserver(() => {\n\t\t\t\tthis.#applyResponsivePaneStyles();\n\t\t\t});\n\t\t\tthis.#resizeObserver.observe(this.#container);\n\t\t} else {\n\t\t\twindow.addEventListener('resize', this.#applyResponsivePaneStyles);\n\t\t}\n\t}\n}\n"],"mappings":";;;;;AAYA,IAAa,aAAb,cAAgC,MAAM;CACrC;;;;;CAMA,YAAmB,MAAsB,SAAiB;EACzD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;CACb;AACD;;;ACPA,SAAS,mBAAmB,OAAqB;CAChD,MAAM,sBAAM,IAAI,IAAsB;CACtC,KAAK,MAAM,QAAQ,OAClB,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC;CAEpB,KAAK,MAAM,QAAQ,OAClB,IAAI,KAAK,WAAW,KAAA,GAAW;EAC9B,MAAM,UAAU,IAAI,IAAI,KAAK,MAAM;EACnC,IAAI,YAAY,KAAA,GACf,QAAQ,KAAK,KAAK,EAAE;CAEtB;CAGD,MAAM,QAAQ,GACb,OAAO,GACP,QAAQ;CACT,MAAM,wBAAQ,IAAI,IAAuB;CACzC,MAAM,yBAAS,IAAI,IAAoB;CAEvC,KAAK,MAAM,MAAM,IAAI,KAAK,GACzB,MAAM,IAAI,IAAI,KAAK;CAGpB,MAAM,OAAO,MAAoB;EAChC,MAAM,IAAI,GAAG,IAAI;EACjB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG;GACjC,MAAM,KAAK,MAAM,IAAI,CAAC,KAAK;GAC3B,IAAI,OAAO,MAAM;IAChB,MAAM,OAAiB,CAAC,GAAG,CAAC;IAC5B,IAAI,MAAM;IACV,OAAO,QAAQ,GAAG;KACjB,MAAM,IAAI,OAAO,IAAI,GAAG;KACxB,IAAI,MAAM,KAAA,GACT;KAED,KAAK,KAAK,CAAC;KACX,MAAM;IACP;IACA,MAAM,IAAI,WAAW,gBAAgB,0BAA0B,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,MAAM,GAAG;GAClG;GACA,IAAI,OAAO,OAAO;IACjB,OAAO,IAAI,GAAG,CAAC;IACf,IAAI,CAAC;GACN;EACD;EACA,MAAM,IAAI,GAAG,KAAK;CACnB;CAEA,KAAK,MAAM,MAAM,IAAI,KAAK,GACzB,KAAK,MAAM,IAAI,EAAE,KAAK,WAAW,OAChC,IAAI,EAAE;AAGT;;;;;;;;;;;AAYA,SAAgB,cAAc,OAA2B;CACxD,MAAM,sBAAM,IAAI,IAAsB;CACtC,MAAM,QAAoB,CAAC;CAG3B,KAAK,MAAM,QAAQ,OAClB,IAAI,KAAK,WAAW,KAAA,GAAW;EAC9B,MAAM,aAAa,MAAM,MAAM,MAAM,EAAE,OAAO,KAAK,MAAM;EACzD,IAAI,eAAe,KAAA,MAAc,WAAW,SAAS,eAAe,WAAW,SAAS,SACvF,MAAM,IAAI,WAAW,oBAAoB,WAAW,KAAK,GAAG,yBAAyB,KAAK,OAAO,YAAY,WAAW,KAAK,EAAE;CAEjI;CAID,KAAK,MAAM,QAAQ,OAClB,IAAI,IAAI,KAAK,IAAI;EAAC,GAAG;EAAM,UAAU,CAAC;EAAG,OAAO;CAAC,CAAC;CAInD,mBAAmB,KAAK;CAGxB,KAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,OAAO,IAAI,IAAI,KAAK,EAAE;EAC5B,IAAI,SAAS,KAAA,GACZ;EAED,IAAI,KAAK,WAAW,KAAA,GAAW;GAC9B,MAAM,SAAS,IAAI,IAAI,KAAK,MAAM;GAClC,IAAI,WAAW,KAAA,GACd,MAAM,IAAI,WAAW,oBAAoB,WAAW,KAAK,GAAG,qCAAqC,KAAK,QAAQ;GAE/G,OAAO,SAAS,KAAK,IAAI;EAC1B,OACC,MAAM,KAAK,IAAI;CAEjB;CAGA,CAAC,SAAS,UAAU,OAAmB,GAAiB;EACvD,KAAK,MAAM,KAAK,OAAO;GACtB,EAAE,QAAQ;GACV,UAAU,EAAE,UAAU,IAAI,CAAC;EAC5B;CACD,GAAG,OAAO,CAAC;CAEX,OAAO;AACR;;;;;;;;;AAUA,SAAgB,YAAY,OAAmB,aAA8C;CAC5F,MAAM,OAAmB,CAAC;CAC1B,SAAS,KAAK,MAAsB;EACnC,KAAK,KAAK,IAAI;EACd,IAAI,KAAK,SAAS,SAAS,KAAK,YAAY,IAAI,KAAK,EAAE,GACtD,KAAK,MAAM,SAAS,KAAK,UACxB,KAAK,KAAK;CAGb;CACA,KAAK,MAAM,QAAQ,OAClB,KAAK,IAAI;CAEV,OAAO;AACR;;;;;;;AAQA,SAAgB,SAAS,MAAyB;CACjD,OAAO,KAAK,SAAS,SAAS;AAC/B;;;;;;;;;;AC3JA,SAAgB,aAAa,OAAe,OAAqB;CAEhE,MAAM,sBAAM,IAAI,IAAsB;CACtC,KAAK,MAAM,QAAQ,OAClB,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC;CAEpB,KAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,YAAY,IAAI,IAAI,KAAK,MAAM;EACrC,IAAI,cAAc,KAAA,GACjB,UAAU,KAAK,KAAK,MAAM;CAE5B;CAEA,MAAM,QAAQ,GACb,OAAO,GACP,QAAQ;CACT,MAAM,wBAAQ,IAAI,IAAuB;CACzC,MAAM,yBAAS,IAAI,IAAoB;CAEvC,KAAK,MAAM,MAAM,IAAI,KAAK,GACzB,MAAM,IAAI,IAAI,KAAK;CAGpB,MAAM,OAAO,MAAoB;EAChC,MAAM,IAAI,GAAG,IAAI;EACjB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG;GACjC,MAAM,KAAK,MAAM,IAAI,CAAC,KAAK;GAC3B,IAAI,OAAO,MAAM;IAEhB,MAAM,OAAiB,CAAC,GAAG,CAAC;IAC5B,IAAI,MAAM;IACV,OAAO,QAAQ,GAAG;KACjB,MAAM,IAAI,OAAO,IAAI,GAAG;KACxB,IAAI,MAAM,KAAA,GACT;KAED,KAAK,KAAK,CAAC;KACX,MAAM;IACP;IACA,MAAM,IAAI,WAAW,oBAAoB,iCAAiC,CAAC,GAAG,IAAI,EAAE,QAAQ,EAAE,KAAK,MAAM,GAAG;GAC7G;GACA,IAAI,OAAO,OAAO;IACjB,OAAO,IAAI,GAAG,CAAC;IACf,IAAI,CAAC;GACN;EACD;EACA,MAAM,IAAI,GAAG,KAAK;CACnB;CAEA,KAAK,MAAM,MAAM,IAAI,KAAK,GACzB,KAAK,MAAM,IAAI,EAAE,KAAK,WAAW,OAChC,IAAI,EAAE;AAGT;;;;;;;;;;;AAYA,SAAgB,iBAAiB,OAAe,OAAqB;CACpE,MAAM,MAAM,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,EAAE,CAAC;CAC1C,MAAM,WAAW,IAAI,IAAI,MAAM,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;CACpD,MAAM,2BAAW,IAAI,IAAY;CAEjC,KAAK,MAAM,QAAQ,OAAO;EACzB,IAAI,CAAC,IAAI,IAAI,KAAK,MAAM,GACvB,MAAM,IAAI,WAAW,kBAAkB,WAAW,KAAK,GAAG,WAAW,KAAK,OAAO,WAAW;EAE7F,IAAI,CAAC,IAAI,IAAI,KAAK,MAAM,GACvB,MAAM,IAAI,WAAW,kBAAkB,WAAW,KAAK,GAAG,WAAW,KAAK,OAAO,WAAW;EAG7F,MAAM,UAAU,GAAG,KAAK,OAAO,GAAG,KAAK;EACvC,IAAI,SAAS,IAAI,OAAO,GACvB,MAAM,IAAI,WAAW,uBAAuB,WAAW,KAAK,GAAG,0BAA0B,KAAK,OAAO,UAAU,KAAK,QAAQ;EAE7H,SAAS,IAAI,OAAO;EAEpB,IAAI,KAAK,SAAS,MAAM;GACvB,MAAM,aAAa,SAAS,IAAI,KAAK,MAAM;GAC3C,MAAM,aAAa,SAAS,IAAI,KAAK,MAAM;GAC3C,IAAI,YAAY,SAAS,eAAe,YAAY,SAAS,aAC5D,MAAM,IAAI,WAAW,uBAAuB,WAAW,KAAK,GAAG,iBAAiB,KAAK,KAAK,4CAA4C;EAExI;CACD;AACD;;;AChFA,MAAM,oBAA+C;CACpD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACL;AAEA,MAAM,kBAA6C;CAClD,IAAI;CACJ,IAAI;AACL;AAEA,MAAM,wBAAsD;CAC3D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACL;AAEA,MAAM,iBAA2C;CAChD,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,CAAC;CACN,IAAI,CAAC,CAAC;CACN,IAAI,CAAC,CAAC;CACN,IAAI,CAAC,CAAC;CACN,IAAI,CAAC,GAAG,CAAC;CACT,IAAI,CAAC,CAAC;CACN,IAAI,CAAC,GAAG,CAAC;AACV;AAEA,MAAa,eAA+C;CAC3D,UAAU;CACV,eAAe;CACf,iBAAiB;CACjB,gBAAgB;CAChB,kBAAkB;CAClB,gBAAgB;CAChB,iBAAiB;CACjB,eAAe;CACf,gBAAgB;CAChB,eAAe;AAChB;AAEA,SAAS,eAAe,MAAsF;CAC7G,IAAI;EACH,IAAI,OAAO,SAAS,eAAe,OAAO,KAAK,WAAW,YAAY;GACrE,MAAM,SAAS,IAAI,KAAK,OAAO,IAAI;GACnC,MAAM,KAAK,OAAO;GAClB,IAAI,OAAO,OAAO,YACjB,OAAO,GAAG,KAAK,MAAM;EAEvB;CACD,QAAQ,CAER;AAED;;;;;;;;;AAUA,SAAgB,mBAAmB,MAAyB;CAC3D,MAAM,UAAU,KAAK,MAAM,GAAG,EAAE,IAAI,YAAY,KAAK;CACrD,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,YAAY;CAE/C,IAAI,WAAW,KAAA,GAAW;EACzB,MAAM,aAAa,kBAAkB;EACrC,IAAI,eAAe,KAAA,GAClB,OAAO;CAET;CACA,MAAM,WAAW,gBAAgB;CACjC,IAAI,aAAa,KAAA,GAChB,OAAO;CAGR,MAAM,OAAO,eAAe,IAAI;CAChC,IAAI,SAAS,KAAA,GAAW;EACvB,MAAM,MAAM,KAAK;EACjB,OAAQ,QAAQ,IAAI,IAAI;CACzB;CAEA,OAAO;AACR;;;;;;;;AASA,SAAgB,oBAAoB,MAAuC;CAC1E,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,YAAY;CAC/C,IAAI,WAAW,KAAA,GAAW;EACzB,MAAM,aAAa,sBAAsB;EACzC,IAAI,eAAe,KAAA,GAClB,OAAO;EAER,IAAI,UAAU,mBACb,OAAO;CAET;CAEA,MAAM,OAAO,eAAe,IAAI;CAChC,IAAI,SAAS,KAAA,GAAW;EACvB,IAAI,KAAK,eAAe,KAAK,KAAK,aAAa,GAC9C,OAAO;EAER,OAAO;CACR;CAEA,OAAO;AACR;;;;;;;;AASA,SAAgB,kBAAkB,MAAwB;CACzD,MAAM,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,YAAY;CAC/C,IAAI,WAAW,KAAA,GAAW;EACzB,MAAM,aAAa,eAAe;EAClC,IAAI,eAAe,KAAA,GAAW;GAC7B,MAAM,OAAO,CAAC,GAAG,UAAU;GAC3B,KAAK,MAAM,GAAG,MAAM,IAAI,CAAC;GACzB,OAAO;EACR;CACD;CAEA,MAAM,OAAO,eAAe,IAAI;CAChC,IAAI,SAAS,KAAA,GAAW;EACvB,MAAM,OAAO,KAAK,QAAQ,KAAK,MAAe,MAAM,IAAI,IAAI,CAAE;EAC9D,KAAK,MAAM,GAAG,MAAM,IAAI,CAAC;EACzB,OAAO;CACR;CAEA,OAAO,CAAC,GAAG,CAAC;AACb;;;;;;;;AASA,SAAgB,mBAAmB,KAAoD;CACtF,IAAI,QAAQ,KAAA,GACX,OAAO;EACN,MAAM;EACN,QAAQ;EACR,cAAc;EACd,eAAe;EACf,aAAa,CAAC,GAAG,CAAC;CACnB;CAED,IAAI,OAAO,QAAQ,UAAU;EAC5B,MAAM,SAAsB;GAC3B,MAAM,IAAI;GACV,cAAc,IAAI,gBAAgB,mBAAmB,IAAI,IAAI;GAC7D,eAAe,IAAI,iBAAiB,oBAAoB,IAAI,IAAI;GAChE,aAAa,IAAI,eAAe,kBAAkB,IAAI,IAAI;EAC3D;EACA,IAAI,IAAI,WAAW,KAAA,GAClB,OAAO,SAAS,IAAI;EAErB,OAAO;CACR;CACA,MAAM,OAAO;CACb,OAAO;EACN;EACA,cAAc,mBAAmB,IAAI;EACrC,eAAe,oBAAoB,IAAI;EACvC,aAAa,kBAAkB,IAAI;CACpC;AACD;AAEA,SAAS,QAAQ,MAAoB;CACpC,MAAM,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,CAAC,CAAC;CACzF,MAAM,SAAS,EAAE,UAAU,KAAK;CAChC,EAAE,WAAW,EAAE,WAAW,IAAI,IAAI,MAAM;CACxC,MAAM,YAAY,IAAI,KAAK,KAAK,IAAI,EAAE,eAAe,GAAG,GAAG,CAAC,CAAC;CAC7D,OAAO,KAAK,OAAO,EAAE,QAAQ,IAAI,UAAU,QAAQ,KAAK,QAAa,KAAK,CAAC;AAC5E;AAEA,SAAS,OAAO,MAAoB;CACnC,MAAM,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,CAAC,CAAC;CACzF,MAAM,YAAY,IAAI,KAAK,KAAK,IAAI,EAAE,eAAe,GAAG,GAAG,CAAC,CAAC;CAC7D,MAAM,YAAY,KAAK,OAAO,EAAE,QAAQ,IAAI,UAAU,QAAQ,KAAK,KAAU;CAC7E,MAAM,UAAU,UAAU,UAAU;CAEpC,MAAM,qBADuB,YAAY,IAAI,IAAI,CAAC;CAElD,IAAI,YAAY,oBACf,OAAO;CAER,OAAO,KAAK,OAAO,YAAY,sBAAsB,CAAC,IAAI;AAC3D;AAEA,SAAS,WAAW,MAAoB;CACvC,MAAM,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,CAAC,CAAC;CACzF,MAAM,YAAY,IAAI,KAAK,KAAK,IAAI,EAAE,eAAe,GAAG,GAAG,CAAC,CAAC;CAC7D,MAAM,YAAY,KAAK,OAAO,EAAE,QAAQ,IAAI,UAAU,QAAQ,KAAK,KAAU;CAC7E,OAAO,KAAK,MAAM,YAAY,KAAK,CAAC;AACrC;;;;;;;;;;;;AAaA,SAAgB,iBAAiB,MAAY,QAAyC;CACrF,QAAQ,QAAR;EACC,KAAK,OACJ,OAAO,QAAQ,IAAI;EAEpB,KAAK,MACJ,OAAO,OAAO,IAAI;EAEnB,KAAK,UACJ,OAAO,WAAW,IAAI;CAExB;AACD;;;;;;;;AASA,SAAgB,YAAY,UAAkB,KAAqB;CAClE,OAAO,SAAS,WAAW,OAAO,GAAG;AACtC;;;;;;;;;;ACvVA,SAAgB,UAAU,SAAuB;CAChD,MAAM,oBAAI,IAAI,KAAK,GAAG,QAAQ,eAAe;CAC7C,IAAI,MAAM,EAAE,QAAQ,CAAC,GACpB,MAAM,IAAI,MAAM,kBAAkB,QAAQ,EAAE;CAE7C,OAAO;AACR;;;;;;;;AASA,SAAgB,QAAQ,MAAY,MAAoB;CACvD,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAU;AACnD;;;;;;;;AASA,SAAgB,SAAS,MAAY,OAAqB;CACzD,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAS;AACnD;;;;;;;;AASA,SAAgB,SAAS,GAAS,GAAiB;CAClD,QAAQ,EAAE,QAAQ,IAAI,EAAE,QAAQ,KAAK;AACtC;;;;;;;;AASA,SAAgB,UAAU,GAAS,GAAiB;CACnD,QAAQ,EAAE,QAAQ,IAAI,EAAE,QAAQ,KAAK;AACtC;;;;;;;AAQA,SAAgB,WAAW,MAAkB;CAC5C,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,CAAC,CAAC;AACvF;AA0DA,SAAS,oBAAoB,QAA6B;CACzD,IAAI,OAAO,QAAQ,kBAAkB,KAAA,GACpC,OAAO,OAAO,OAAO;CAEtB,OAAO,aAAa;AACrB;;;;;;;;;AAUA,SAAgB,kBAAkB,MAAY,OAAkB,QAA6B;CAC5F,MAAM,EAAC,MAAM,eAAe,gBAAgB,UAAS;CACrD,QAAQ,OAAR;EACC,KAAK,QACJ,OAAO,GAAG,OAAO,KAAK,YAAY,CAAC,EAAE,SAAS,GAAG,GAAG,EAAE;EAEvD,KAAK,OAAO;GACX,MAAM,MAAM,KAAK,mBAAmB,MAAM;IAAC,SAAS;IAAS,UAAU;GAAK,CAAC;GAC7E,OAAO,GAAG,KAAK,WAAW,EAAE,GAAG;EAChC;EACA,KAAK,QAEJ,OAAO,IADI,iBAAiB,MAAM,aACtB;EAEb,KAAK,SACJ,OAAO,KAAK,mBAAmB,MAAM;GAAC,OAAO;GAAS,MAAM;GAAW,UAAU;EAAK,CAAC;EAExF,KAAK,WACJ,OAAO,GAAG,oBAAoB,MAAM,IAAI,KAAK,MAAM,KAAK,YAAY,IAAI,CAAC,IAAI,EAAE,GAAG,KAAK,eAAe;EAEvG,KAAK,QACJ,OAAO,GAAG,KAAK,eAAe;CAEhC;AACD;;;;;;;;;;AAWA,SAAgB,iBAAiB,MAAY,OAAkB,QAA6B;CAC3F,MAAM,EAAC,SAAQ;CACf,QAAQ,OAAR;EACC,KAAK,QACJ,OAAO,KAAK,mBAAmB,MAAM;GAAC,OAAO;GAAQ,KAAK;GAAW,MAAM;GAAW,UAAU;EAAK,CAAC;EAEvG,KAAK;EACL,KAAK,QACJ,OAAO,KAAK,mBAAmB,MAAM;GAAC,OAAO;GAAQ,MAAM;GAAW,UAAU;EAAK,CAAC;EAEvF,KAAK,SACJ,OAAO,GAAG,KAAK,eAAe;EAE/B,KAAK,WACJ,OAAO,GAAG,KAAK,eAAe;EAE/B,KAAK,QACJ,OAAO,GAAG,KAAK,eAAe;CAEhC;AACD;;;;;;;;AASA,SAAgB,aAAa,OAAa,KAAmB;CAC5D,OAAO,KAAK,MAAM,SAAS,OAAO,GAAG,CAAC,IAAI;AAC3C;;;;;;;;AAoBA,SAAgB,kBAAkB,SAAiB,QAA6B;CAE/E,OADU,UAAU,OACb,EAAE,mBAAmB,OAAO,MAAM;EAAC,MAAM;EAAW,OAAO;EAAW,KAAK;EAAW,UAAU;CAAK,CAAC;AAC9G;;;AC9NA,MAAM,IAAI;AACV,MAAM,IAAI;AAEV,MAAa,gBAAgD;CAC5D,MAAM;EAAC,aAAa;EAAI,aAAa;EAAG,cAAc;CAAM;CAC5D,KAAK;EAAC,aAAa;EAAI,aAAa;EAAG,cAAc;CAAK;CAC1D,MAAM;EAAC,aAAa;EAAK,aAAa,IAAI;EAAG,cAAc;CAAM;CACjE,OAAO;EAAC,aAAa;EAAK,aAAa,KAAK;EAAG,cAAc;CAAO;CACpE,SAAS;EAAC,aAAa;EAAK,aAAa,KAAK;EAAG,cAAc;CAAS;CACxE,MAAM;EAAC,aAAa;EAAK,aAAa,MAAM;EAAG,cAAc;CAAM;AACpE;;;;;;;;;;;AAYA,SAAgB,oBAAoB,MAAY,OAAkB,eAA0B,GAAS;CACpG,QAAQ,OAAR;EACC,KAAK,QACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,GAAG,KAAK,YAAY,CAAC,CAAC;EAE3G,KAAK,OACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,CAAC,CAAC;EAEvF,KAAK,QAAQ;GACZ,MAAM,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,KAAK,WAAW,CAAC,CAAC;GAEzF,MAAM,WADM,EAAE,UACM,IAAI,gBAAgB,IAAK,KAAK;GAClD,EAAE,WAAW,EAAE,WAAW,IAAI,MAAM;GACpC,OAAO;EACR;EACA,KAAK,SACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,GAAG,CAAC,CAAC;EAEvE,KAAK,WAAW;GACf,MAAM,QAAQ,KAAK,YAAY;GAC/B,MAAM,oBAAoB,KAAK,MAAM,QAAQ,CAAC,IAAI;GAClD,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,mBAAmB,CAAC,CAAC;EACtE;EACA,KAAK,QACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,GAAG,CAAC,CAAC;CAEvD;AACD;;;;;;;;;AAUA,SAAgB,kBAAkB,MAAY,OAAwB;CACrE,QAAQ,OAAR;EACC,KAAK,QACJ,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,CAAC;EAEnC,KAAK,OACJ,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,CAAC;EAEnC,KAAK,QACJ,OAAO,IAAI,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC;EAEvC,KAAK,SACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,IAAI,GAAG,CAAC,CAAC;EAE3E,KAAK,WACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,GAAG,KAAK,YAAY,IAAI,GAAG,CAAC,CAAC;EAE3E,KAAK,QACJ,OAAO,IAAI,KAAK,KAAK,IAAI,KAAK,eAAe,IAAI,GAAG,GAAG,CAAC,CAAC;CAE3D;AACD;;;;;;;;;;AAWA,SAAgB,oBAAoB,MAAY,OAAkB,eAA0B,GAAS;CACpG,MAAM,QAAQ,oBAAoB,MAAM,OAAO,YAAY;CAC3D,IAAI,MAAM,QAAQ,MAAM,KAAK,QAAQ,GACpC,OAAO;CAER,OAAO,kBAAkB,OAAO,KAAK;AACtC;;;;;;;;;;;ACjFA,SAAgB,kBAAkB,OAAkB,eAAkC;CACrF,MAAM,EAAC,aAAa,gBAAe,cAAc;CACjD,MAAM,WAAW,cAAc,QAAQ;CACvC,MAAM,UAAU,cAAc;CAC9B,MAAM,UAAU,cAAc;CAC9B,MAAM,WAAW;CAEjB,OAAO;EACN;EACA;EACA,IAAI,MAAoB;GACvB,QAAQ,KAAK,QAAQ,IAAI,YAAY;EACtC;EACA,OAAO,GAAiB;GACvB,OAAO,IAAI,KAAK,WAAW,IAAI,OAAO;EACvC;EACA,oBAAoB,MAAsB;GACzC,OAAO,OAAO,WAAW;EAC1B;EACA,oBAAoB,IAAoB;GACvC,OAAQ,KAAK,UAAW;EACzB;CACD;AACD;;;AC7CA,MAAa,UAAU;CACtB,WAAW;CACX,WAAW;CACX,eAAe;AAChB;AAEA,MAAa,aAAa,QAAQ;AAClC,MAAa,aAAa,QAAQ;AAClC,MAAa,gBAAgB,aAAa,cAAc;AACxD,MAAa,iBAAiB,QAAQ;;AAEtC,MAAa,iBAAiB,iBAAiB;;;;;;;;;AA0B/C,SAAgB,cAAc,MAAkB,QAA6C;CAC5F,MAAM,yBAAS,IAAI,IAAuB;CAE1C,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACrC,MAAM,OAAO,KAAK;EAClB,IAAI,SAAS,KAAA,GACZ;EAGD,MAAM,QAAQ,UAAU,KAAK,SAAS;EACtC,MAAM,IAAI,OAAO,IAAI,KAAK;EAC1B,MAAM,IAAI,IAAI,aAAa;EAC3B,MAAM,UAAU,IAAI,aAAa,aAAa;EAE9C,IAAI,KAAK,SAAS,aAAa;GAC9B,OAAO,IAAI,KAAK,IAAI;IACnB,QAAQ,KAAK;IACb;IACA;IACA,OAAO;IACP,QAAQ;IACR,eAAe;IACf,MAAM;IACN,UAAU;IACV,SAAS;IACT;GACD,CAAC;GACD;EACD;EAGA,MAAM,OAAO,aAAa,OADd,UAAU,KAAK,OACQ,CAAC;EACpC,MAAM,QAAQ,KAAK,IAAI,OAAO,oBAAoB,IAAI,GAAG,CAAC;EAC1D,MAAM,gBAAgB,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,mBAAmB,KAAK,GAAG,CAAC;EAExF,OAAO,IAAI,KAAK,IAAI;GACnB,QAAQ,KAAK;GACb;GACA;GACA;GACA,QAAQ;GACR;GACA,MAAM,KAAK;GACX,UAAU;GACV,SAAS,IAAI,QAAQ;GACrB;EACD,CAAC;CACF;CAEA,OAAO;AACR;;;;;;;AAQA,SAAgB,mBAAmB,UAA0B;CAC5D,OAAO,WAAW;AACnB;;;;;;;;AASA,SAAgB,eAAe,OAAmB,eAAe,IAAkB;CAClF,IAAI,MAAM,WAAW,GAAG;EACvB,MAAM,sBAAM,IAAI,KAAK;EACrB,OAAO,CAAC,KAAK,SAAS,KAAK,GAAG,CAAC;CAChC;CAEA,IAAI,QAAQ;CACZ,IAAI,QAAQ;CAEZ,KAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,QAAQ,UAAU,KAAK,SAAS;EACtC,IAAI,MAAM,QAAQ,IAAI,OACrB,QAAQ,MAAM,QAAQ;EAEvB,IAAI,KAAK,SAAS,aAAa;GAC9B,MAAM,MAAM,UAAU,KAAK,OAAO;GAClC,IAAI,IAAI,QAAQ,IAAI,OACnB,QAAQ,IAAI,QAAQ;EAEtB,OAAO,IAAI,MAAM,QAAQ,IAAI,OAC5B,QAAQ,MAAM,QAAQ;CAExB;CAEA,OAAO,CAAC,SAAS,IAAI,KAAK,KAAK,GAAG,CAAC,YAAY,GAAG,SAAS,IAAI,KAAK,KAAK,GAAG,YAAY,CAAC;AAC1F;;;;ACvHA,MAAM,cAAc;;AAGpB,MAAM,kBAAkB;;AAGxB,MAAM,iBAAiB;;;;;;;;;AAUvB,SAAS,cAAc,QAA0B;CAChD,MAAM,MAAe,CAAC;CACtB,KAAK,MAAM,MAAM,QAAQ;EACxB,MAAM,OAAO,IAAI,GAAG,EAAE;EACtB,IAAI,SAAS,KAAA,KAAa,KAAK,MAAM,GAAG,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,CAAC,KAAK,gBACrE,IAAI,KAAK,EAAE;CAEb;CACA,OAAO;AACR;;;;;;;;;;;;;;AAiBA,SAAS,YAAY,MAA6B;CACjD,OAAO,SAAS,QAAQ,SAAS;AAClC;;;;;;;;;;;;;;AAeA,SAAS,YAAY,MAA6B;CACjD,OAAO,SAAS,QAAQ,SAAS;AAClC;;;;;;;;;;;;;;;;;;;;AAqBA,SAAS,WAAW,MAAoB,KAAgB,KAA0C;CACjG,MAAM,WAAW,IAAI,SAAS,cAAc,IAAI,IAAI,iBAAiB,IAAI,IAAI,IAAI;CACjF,MAAM,UAAU,IAAI,SAAS,cAAc,IAAI,IAAI,iBAAiB,IAAI;CACxE,MAAM,WAAW,IAAI,SAAS,cAAc,IAAI,IAAI,iBAAiB,IAAI,IAAI,IAAI;CACjF,MAAM,UAAU,IAAI,SAAS,cAAc,IAAI,IAAI,iBAAiB,IAAI;CAExE,QAAQ,MAAR;EACC,KAAK,MACJ,OAAO;GAAC,IAAI;GAAU,IAAI;EAAO;EAElC,KAAK,MACJ,OAAO;GAAC,IAAI;GAAS,IAAI;EAAO;EAEjC,KAAK,MACJ,OAAO;GAAC,IAAI;GAAU,IAAI;EAAQ;EAEnC,KAAK,MACJ,OAAO;GAAC,IAAI;GAAS,IAAI;EAAQ;EAElC,SAEC,MAAM,IAAI,MAAM,wBAAwB,OAAOA,IAAW,GAAG;CAE/D;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAS,aAAa,IAAY,IAAY,IAAY,IAAY,WAAoB,WAAoB,QAAQ,OAAgB;CAErI,IAAI,KAAK,IAAI,KAAK,EAAE,KAAK;MACN,aAAa,KAAK,MAAQ,CAAC,aAAa,KAAK,IAE9D,OAAO,CACN;GAAC,GAAG;GAAI,GAAG;EAAE,GACb;GAAC,GAAG;GAAI,GAAG;EAAE,CACd;CAAA;CAgCF,MAAM,UAAU,YAAY,cAAc;CAC1C,MAAM,UAAU,MAAM,QAAQ,MAAmB;CACjD,MAAM,YAAY,YAAY,KAAK,cAAc,KAAK;CAEtD,OAAO;EACN;GAAC,GAAG;GAAI,GAAG;EAAE;EACb;GAAC,GAAG,KAAK;GAAS,GAAG;EAAE;EACvB;GAAC,GAAG,KAAK;GAAS,GAAG;EAAO;EAC5B;GAAC,GAAG;GAAW,GAAG;EAAO;EACzB;GAAC,GAAG;GAAW,GAAG;EAAE;EACpB;GAAC,GAAG;GAAI,GAAG;EAAE;CACd;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CA,SAAS,cAAc,IAAY,IAAY,IAAY,IAAY,WAAoB,WAA6B;CAEvH,MAAM,OADY,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,IAAI,UAC5B,IAAI,MAAM,KAAK,KAAK,MAAM,IAAI,aAAa,KAAK,KAAK,MAAM;CAChF,MAAM,YAAY,YAAY,KAAK,cAAc,KAAK;CACtD,MAAM,SAAS,YAAY,KAAK,IAAI,KAAK,aAAa,SAAS,IAAI,KAAK,IAAI,KAAK,aAAa,SAAS;CAEvG,OAAO;EACN;GAAC,GAAG;GAAI,GAAG;EAAE;EACb;GAAC,GAAG;GAAQ,GAAG;EAAE;EACjB;GAAC,GAAG;GAAQ,GAAG;EAAI;EACnB;GAAC,GAAG;GAAW,GAAG;EAAI;EACtB;GAAC,GAAG;GAAW,GAAG;EAAE;EACpB;GAAC,GAAG;GAAI,GAAG;EAAE;CACd;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,SAAS,MAAM,MAAoB,KAAgB,KAAyB;CAC3E,MAAM,EAAC,IAAI,OAAM,WAAW,MAAM,KAAK,GAAG;CAC1C,MAAM,KAAK,IAAI;CACf,MAAM,KAAK,IAAI;CAEf,MAAM,YAAY,YAAY,IAAI;CAClC,MAAM,YAAY,YAAY,IAAI;CAIlC,OAAO,cAFK,KAAK,IAAI,KAAK,EAAE,IAAI,IAAI,aAAa,IAAI,IAAI,IAAI,IAAI,WAAW,SAAS,IAAI,cAAc,IAAI,IAAI,IAAI,IAAI,WAAW,SAAS,CAEnH;AACzB;;;;;;;;;;AAaA,SAAgB,WAAW,OAAe,SAA+C;CACxF,OAAO,MACL,KAAK,SAAS;EACd,MAAM,MAAM,QAAQ,IAAI,KAAK,MAAM;EACnC,MAAM,MAAM,QAAQ,IAAI,KAAK,MAAM;EACnC,IAAI,QAAQ,KAAA,KAAa,QAAQ,KAAA,GAChC,OAAO;EAER,OAAO;GACN,QAAQ,KAAK;GACb,cAAc,KAAK;GACnB,cAAc,KAAK;GACnB,MAAM,KAAK;GACX,QAAQ,MAAM,KAAK,MAAM,KAAK,GAAG;EAClC;CACD,CAAC,EACA,QAAQ,MAAuB,MAAM,IAAI;AAC5C;;;AC7VA,MAAa,iBAAiB,EAAE,KAAK;CAAC;CAAM;CAAM;CAAM;AAAI,CAAC;AAC/B,EAAE,KAAK;CAAC;CAAQ;CAAW;AAAW,CAAC;AACrE,MAAM,uBAAuB,EAAE,KAAK,CAAC,WAAW,QAAQ,CAAC;;AAGzD,MAAa,mBAAmB,EAAE,OAAO;;CAExC,MAAM,EAAE,OAAO,EAAE,MAAM,wBAAwB,qBAAqB;CACpE,MAAM;CACN,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;CAClC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS;AACvC,CAAC;AAED,MAAM,WAAW;;CAEhB,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;;CAE9B,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;;CAEtB,WAAW,EAAE,OAAO,EAAE,MAAM,wBAAwB,qBAAqB;;CAEzE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;;CAE7C,OAAO,EAAE,OAAO,EAAE,SAAS;;CAE3B,UAAU,EAAE,QAAQ,EAAE,SAAS;;CAE/B,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAClD;;AAGA,MAAM,iBAAiB,EACrB,OAAO;CACP,GAAG;CACH,MAAM,EAAE,QAAQ,MAAM;;CAEtB,SAAS,EAAE,OAAO,EAAE,MAAM,wBAAwB,qBAAqB;;CAEvE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,CAAC;AAC5D,CAAC,EACA,QAAQ,MAAM,EAAE,WAAW,EAAE,WAAW;CAAC,SAAS;CAAyC,MAAM,CAAC,SAAS;AAAC,CAAC;;AAG/G,MAAM,oBAAoB,EACxB,OAAO;CACP,GAAG;CACH,MAAM,EAAE,QAAQ,SAAS;;CAEzB,SAAS,EAAE,OAAO,EAAE,MAAM,wBAAwB,qBAAqB;;CAEvE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,CAAC;;;;;;;CAO3D,MAAM,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAC/B,CAAC,EACA,QAAQ,MAAM,EAAE,WAAW,EAAE,WAAW;CAAC,SAAS;CAAyC,MAAM,CAAC,SAAS;AAAC,CAAC;;AAG/G,MAAM,sBAAsB,EAAE,OAAO;CACpC,GAAG;CACH,MAAM,EAAE,QAAQ,WAAW;AAC5B,CAAC;AAED,MAAM,aAAa,EAAE,mBAAmB,QAAQ;CAAC;CAAgB;CAAmB;AAAmB,CAAC;AAExG,MAAM,aAAa,EACjB,OAAO;;CAEP,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;;CAE9B,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;;CAElC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;;;;;;;;;;;CAWlC,MAAM,eAAe,QAAQ,IAAI;;CAEjC,UAAU,EAAE,QAAQ,EAAE,SAAS;;CAE/B,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAClD,CAAC,EACA,QAAQ,MAAM,EAAE,WAAW,EAAE,QAAQ;CACrC,SAAS;CACT,MAAM,CAAC,QAAQ;AAChB,CAAC;;AAGF,MAAa,mBAAmB,EAC9B,OAAO;;CAEP,OAAO,EAAE,MAAM,UAAU,EAAE,IAAI,CAAC;;CAEhC,OAAO,EAAE,MAAM,UAAU,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC,EACA,aAAa,MAAM,QAAQ;CAE3B,MAAM,0BAAU,IAAI,IAAY;CAChC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;EAC3C,MAAM,OAAO,KAAK,MAAM;EACxB,IAAI,SAAS,KAAA,GAAW;GACvB,IAAI,QAAQ,IAAI,KAAK,EAAE,GACtB,IAAI,SAAS;IACZ,MAAM;IACN,SAAS,sBAAsB,KAAK;IACpC,MAAM;KAAC;KAAS;KAAG;IAAI;GACxB,CAAC;GAEF,QAAQ,IAAI,KAAK,EAAE;EACpB;CACD;CAGA,MAAM,0BAAU,IAAI,IAAY;CAChC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;EAC3C,MAAM,OAAO,KAAK,MAAM;EACxB,IAAI,SAAS,KAAA,GAAW;GACvB,IAAI,QAAQ,IAAI,KAAK,EAAE,GACtB,IAAI,SAAS;IACZ,MAAM;IACN,SAAS,sBAAsB,KAAK;IACpC,MAAM;KAAC;KAAS;KAAG;IAAI;GACxB,CAAC;GAEF,QAAQ,IAAI,KAAK,EAAE;EACpB;CACD;CAGA,MAAM,2BAAW,IAAI,IAAY;CACjC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;EAC3C,MAAM,OAAO,KAAK,MAAM;EACxB,IAAI,SAAS,KAAA,GAAW;GACvB,MAAM,MAAM,GAAG,KAAK,OAAO,GAAG,KAAK;GACnC,IAAI,SAAS,IAAI,GAAG,GACnB,IAAI,SAAS;IACZ,MAAM;IACN,SAAS,+BAA+B,KAAK,OAAO,UAAU,KAAK;IACnE,MAAM,CAAC,SAAS,CAAC;GAClB,CAAC;GAEF,SAAS,IAAI,GAAG;EACjB;CACD;AACD,CAAC;;;;;;;;;ACvJF,SAAgB,IAAI,MAAmB,QAA4C;CAClF,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,GAEzC,KAAM,MAAc,KAAK,KAAK;AAEhC;AAWA,SAAgB,GAAG,KAAa,OAAiC,IAAsB;CACtF,MAAM,OAAO,KAAK,SAAS,gBAAgB,IAAI,GAAG,IAAI,SAAS,cAAc,GAAG;CAChF,IAAI,UAAU,KAAA,GACb,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,KAAK,GACxC,IAAI,MAAM,WAAW,OAAO,MAAM,YAAY,MAAM,MACnD,IAAI,MAAqB,CAAiC;MACpD,IAAI,KAAK,MAEf,KAAc,KAAK;MAEnB,KAAK,aAAa,GAAG,OAAO,CAAC,CAAC;CAIjC,OAAO;AACR;;;;;;AAOA,SAAgB,cAAc,MAAqB;CAClD,OAAO,KAAK,eAAe,MAC1B,KAAK,YAAY,KAAK,UAAU;AAElC;;;;;;;AAQA,SAAgB,UAAU,QAAiB,UAAoC;CAC9E,MAAM,OAAO,SAAS,uBAAuB;CAC7C,KAAK,MAAM,KAAK,UACf,KAAK,YAAY,CAAC;CAEnB,OAAO,OAAO,IAAI;AACnB;;;;;;;AA0BA,SAAgB,SAAS,MAAe,OAA8C;CACrF,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,KAAK,GACxC,KAAK,aAAa,GAAG,OAAO,CAAC,CAAC;AAEhC;;;ACrFA,SAAS,eACR,MACA,mBACA,cACA,aAC0C;CAC1C,MAAM,UAAU,WAAW,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;CAC1D,MAAM,aAAa,kBAAkB,IAAI,OAAO;CAChD,IAAI,eAAe,KAAA,GAClB,OAAO,WAAW;CAEnB,IAAI,gBAAgB,YAAY,IAAI,KAAK,UAAU,CAAC,GACnD,OAAO;CAER,OAAO;AACR;;;;;;;AAQA,SAAS,KAAK,MAAmB,QAA4C;CAC5E,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,GAEzC,KAAM,MAAc,KAAK,KAAK;AAEhC;;;;;;;;AASA,SAAgB,iBAAiB,WAAwB,OAAyB;CACjF,MAAM,EAAC,OAAO,eAAe,aAAa,QAAQ,YAAY,QAAQ,cAAc,aAAa,sBAAqB;CACtH,MAAM,eAAe,OAAO,gBAAgB;CAE5C,MAAM,aAAqB,CAAC;CAC5B,MAAM,aAAsE,CAAC;CAE7E,IAAI,MAAM,oBAAoB,eAAe,OAAO,YAAY;CAChE,IAAI,iBAAiB;CACrB,IAAI,aAAa;CACjB,IAAI,aAAa;CAEjB,OAAO,MAAM,aAAa;EACzB,MAAM,OAAO,kBAAkB,KAAK,KAAK;EACzC,MAAM,IAAI,OAAO,IAAI,GAAG;EACxB,MAAM,IAAI,OAAO,IAAI,IAAI,IAAI;EAC7B,WAAW,KAAK;GAAC,OAAO,kBAAkB,KAAK,OAAO,MAAM;GAAG;GAAG,OAAO;GAAG,MAAM,IAAI,KAAK,GAAG;EAAC,CAAC;EAEhG,MAAM,SAAS,iBAAiB,KAAK,OAAO,MAAM;EAClD,IAAI,WAAW,gBAAgB;GAC9B,IAAI,mBAAmB,IACtB,WAAW,KAAK;IAAC,OAAO;IAAgB,GAAG;IAAY,OAAO;GAAU,CAAC;GAE1E,iBAAiB;GACjB,aAAa;GACb,aAAa;EACd,OACC,cAAc;EAEf,MAAM;CACP;CACA,IAAI,mBAAmB,IACtB,WAAW,KAAK;EAAC,OAAO;EAAgB,GAAG;EAAY,OAAO;CAAU,CAAC;CAI1E,MAAM,WAAW,GAAG,KAAK;CACzB,KAAK,UAAU;EACd,UAAU;EACV,QAAQ;EACR,OAAO,GAAG,WAAW;EACrB,YAAY;EACZ,cAAc;CACf,CAAC;CAED,MAAM,aAAa,WAAW,KAAK,SAAS;EAC3C,MAAM,IAAI,GAAG,KAAK;EAClB,KAAK,GAAG;GACP,UAAU;GACV,MAAM,GAAG,KAAK,EAAE;GAChB,OAAO,GAAG,KAAK,MAAM;GACrB,QAAQ;GACR,aAAa;GACb,SAAS;GACT,YAAY;GACZ,aAAa;GACb,UAAU;GACV,YAAY;GACZ,OAAO;GACP,UAAU;GACV,YAAY;GACZ,eAAe;GACf,eAAe;EAChB,CAAC;EACD,EAAE,cAAc,KAAK;EACrB,OAAO;CACR,CAAC;CAGD,MAAM,WAAW,GAAG,KAAK;CACzB,KAAK,UAAU;EACd,UAAU;EACV,QAAQ;EACR,OAAO,GAAG,WAAW;EACrB,YAAY;EACZ,cAAc;CACf,CAAC;CAED,MAAM,aAAa,WAAW,KAAK,SAAS;EAC3C,MAAM,IAAI,GAAG,KAAK;EAClB,KAAK,GAAG;GACP,UAAU;GACV,MAAM,GAAG,KAAK,EAAE;GAChB,OAAO,GAAG,KAAK,MAAM;GACrB,QAAQ;GACR,aAAa;GACb,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,UAAU;GACV,OAAO;GACP,UAAU;GACV,YAAY;EACb,CAAC;EACD,EAAE,cAAc,KAAK;EAErB,IAAI,UAAU,OAAO;GACpB,MAAM,OAAO,eAAe,KAAK,MAAM,mBAAmB,cAAc,WAAW;GACnF,IAAI,SAAS,MAAM;IAClB,EAAE,UAAU,IAAI,sBAAsB,MAAM;IAC5C,MAAM,UAAU,WAAW,KAAK,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;IAC/D,EAAE,QAAQ,UAAU;IACpB,MAAM,aAAa,kBAAkB,IAAI,OAAO;IAChD,IAAI,YAAY,UAAU,KAAA,GAAW;KACpC,EAAE,QAAQ,WAAW,WAAW;KAChC,EAAE,QAAQ,WAAW;IACtB;GACD;EACD;EAEA,OAAO;CACR,CAAC;CAED,UAAU,UAAU,UAAU;CAC9B,UAAU,UAAU,UAAU;CAE9B,cAAc,SAAS;CACvB,UAAU,OAAO,QAAQ;CACzB,UAAU,OAAO,QAAQ;AAC1B;;;AC7IA,MAAa,uBAAqC;CACjD;EACC,IAAI;EACJ,QAAQ;EACR,OAAO;CACR;CACA;EACC,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,OAAO;EACP,SAAS,OAAO,OAAO,MAAM,WAAW,kBAAkB,OAAiB,MAAM;CAClF;CACA;EACC,IAAI;EACJ,QAAQ;EACR,OAAO;CACR;AACD;;;;;;;;AASA,SAAgB,mBAAmB,QAAmC;CACrE,OAAO;EACN;GACC,IAAI;GACJ,QAAQ,OAAO,QAAQ,kBAAkB,aAAa;GACtD,OAAO;EACR;EACA;GACC,IAAI;GACJ,QAAQ,OAAO,QAAQ,mBAAmB,aAAa;GACvD,OAAO;GACP,OAAO;GACP,SAAS,OAAO,OAAO,MAAM,QAAQ,kBAAkB,OAAO,KAAK,GAAG,GAAG;EAC1E;EACA;GACC,IAAI;GACJ,QAAQ;GACR,OAAO;EACR;CACD;AACD;;;;;;;AAQA,SAAgB,oBAAoB,SAA+B;CAClE,OAAO,QACL,QAAQ,MAAM,EAAE,YAAY,KAAK,EACjC,KAAK,MAAM,EAAE,KAAK,EAClB,KAAK,GAAG;AACX;;;;;;;AAQA,SAAgB,eAAe,SAAqC;CACnE,OAAO,QAAQ,QAAQ,MAAM,EAAE,YAAY,KAAK;AACjD;AAEA,MAAa,2BAA2B;AAExC,MAAM,QAAQ;AACd,MAAM,QAAQ;AAEd,SAAS,oBAAoB,OAAuB;CACnD,MAAM,UAAU,MAAM,KAAK;CAC3B,MAAM,UAAU,MAAM,KAAK,OAAO;CAClC,IAAI,SACH,OAAO,WAAW,QAAQ,MAAM,GAAG;CAEpC,MAAM,UAAU,MAAM,KAAK,OAAO;CAClC,IAAI,SACH,OAAO,WAAW,QAAQ,MAAM,GAAG,IAAA;CAEpC,OAAO;AACR;;;;;;;;AASA,SAAgB,iBAAiB,SAA+B;CAC/D,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,eAAe,OAAO,GACvC,SAAS,oBAAoB,IAAI,KAAK;CAEvC,OAAO;AACR;;;ACpHA,MAAM,SAAS;AACf,MAAM,mBAAmB;AAUzB,SAAgBC,SAAO,MAAsB;CAC5C,MAAM,OAAO;EACZ,IAAI,KAAK;EACT,MAAM,KAAK;EACX,WAAW,KAAK;EAChB,GAAI,KAAK,WAAW,KAAA,IAAY,CAAC,IAAI,EAAC,QAAQ,KAAK,OAAM;EACzD,GAAI,KAAK,UAAU,KAAA,IAAY,CAAC,IAAI,EAAC,OAAO,KAAK,MAAK;EACtD,GAAI,KAAK,SAAS,KAAA,IAAY,CAAC,IAAI,EAAC,MAAM,KAAK,KAAI;CACpD;CAEA,QAAQ,KAAK,MAAb;EACC,KAAK,QACJ,OAAO;GACN,GAAG;GACH,MAAM;GACN,SAAS,KAAK;GACd,iBAAiB,KAAK;EACvB;EAED,KAAK,WACJ,OAAO;GACN,GAAG;GACH,MAAM;GACN,SAAS,KAAK;GACd,iBAAiB,KAAK;GACtB,MAAM,KAAK;EACZ;EAED,KAAK,aACJ,OAAO;GAAC,GAAG;GAAM,MAAM;EAAW;CAEpC;AACD;AAEA,SAAS,aAAa,MAAY,OAAwB;CACzD,QAAQ,OAAR;EACC,KAAK,WACJ,OAAO,KAAK,SAAS,cAAc,KAAK,UAAU,KAAA;EAEnD,KAAK,mBACJ,OAAO,KAAK,SAAS,cAAc,KAAK,kBAAkB,KAAA;EAE3D,KAAK,QACJ,OAAO,KAAK,SAAS,YAAY,KAAK,OAAO,KAAA;EAE9C,SACC,OAAQ,KAAiC;CAE3C;AACD;AAEA,SAAS,kBAAkB,KAAe,aAA0B,KAAqC;CACxG,MAAM,cAAc,SAAS,GAAG;CAChC,MAAM,WAAW,YAAY,IAAI,IAAI,EAAE;CAEvC,MAAM,OAAO,GAAG,KAAK;CACrB,IAAI,MAAM;EACT,SAAS;EACT,YAAY;EACZ,aAAa,GAAG,IAAI,QAAQ,OAAO;EACnC,KAAK;EACL,UAAU;CACX,CAAC;CAED,IAAI,aAAa;EAChB,MAAM,MAAM,GAAG,QAAQ;EACvB,IAAI,YAAY;EAChB,IAAI,cAAc,WAAW,MAAW;EACxC,IAAI,KAAK;GACR,OAAO;GACP,QAAQ;GACR,SAAS;GACT,YAAY;GACZ,gBAAgB;GAChB,YAAY;GACZ,QAAQ;GACR,QAAQ;GACR,OAAO;GACP,SAAS;GACT,YAAY;EACb,CAAC;EACD,IAAI,iBAAiB,UAAU,MAAM;GACpC,EAAE,gBAAgB;GAClB,IAAI,SAAS,IAAI,EAAE;EACpB,CAAC;EACD,KAAK,OAAO,GAAG;CAChB,OAAO;EACN,MAAM,SAAS,GAAG,MAAM;EACxB,OAAO,MAAM,QAAQ;EACrB,OAAO,MAAM,aAAa;EAC1B,KAAK,OAAO,MAAM;CACnB;CAEA,MAAM,QAAQ,GAAG,MAAM;CACvB,IAAI,OAAO;EACV,UAAU;EACV,YAAY,IAAI,SAAS,YAAY,kCAAkC;EACvE,OAAO;EACP,UAAU;EACV,cAAc;EACd,YAAY;CACb,CAAC;CACD,MAAM,cAAc,IAAI;CACxB,KAAK,OAAO,KAAK;CAEjB,OAAO;AACR;AAEA,SAAS,cAAc,KAAe,QAAoB,QAAkC;CAC3F,MAAM,OAAO,GAAG,MAAM;CACtB,MAAM,SAAuC;EAC5C,UAAU;EACV,OAAO;EACP,cAAc;EACd,UAAU;EACV,cAAc;EACd,YAAY;CACb;CACA,IAAI,OAAO,UAAU,KAAA,GACpB,OAAO,YAAY,OAAO;CAE3B,IAAI,MAAM,MAAM;CAEhB,MAAM,OAAOA,SAAO,GAAG;CACvB,IAAI,OAAO,UAAU,KAAA,GAAW;EAC/B,MAAM,WAAW,aAAa,MAAM,OAAO,KAAK;EAChD,IAAI,OAAO,WAAW,KAAA,GACrB,KAAK,cAAc,OAAO,OAAO,UAAU,MAAM,KAAK,MAAM;OAE5D,KAAK,cACJ,aAAa,QAAQ,aAAa,KAAA,IAC/B,OAAO,aAAa,WACnB,KAAK,UAAU,QAAQ,IACvB,OAAO,QAAqC,IAC7C;CAEN;CAEA,OAAO;AACR;AAEA,SAAS,eAAe,KAAe,KAAwB,QAAkC;CAChG,MAAM,MAAM,GAAG,QAAQ;CACvB,IAAI,YAAY;CAChB,IAAI,cAAc;CAClB,IAAI,QAAQ,OAAO,QAAQ,mBAAmB,aAAa;CAC3D,IAAI,KAAK;EACR,YAAY;EACZ,QAAQ;EACR,QAAQ;EACR,OAAO;EACP,UAAU;EACV,YAAY;CACb,CAAC;CACD,IAAI,iBAAiB,UAAU,UAAU;EACxC,MAAM,gBAAgB;EACtB,IAAI,UAAU,IAAI,EAAE;CACrB,CAAC;CAED,OAAO;AACR;AAEA,SAAS,0BAAuC;CAE/C,OADY,GAAG,KACN;AACV;AAEA,SAAS,UACR,QACA,KACA,aACA,KACA,QACA,mBACc;CACd,QAAQ,OAAO,IAAf;EACC,KAAK,QACJ,OAAO,kBAAkB,KAAK,aAAa,GAAG;EAE/C,KAAK,WACJ,OAAO,oBAAoB,eAAe,KAAK,KAAK,MAAM,IAAI,wBAAwB;EAEvF,SACC,OAAO,cAAc,KAAK,QAAQ,MAAM;CAE1C;AACD;AAEA,SAAS,SACR,KACA,YACA,aACA,KACA,SACA,QACA,mBACc;CACd,MAAM,WAAW,IAAI,OAAO;CAE5B,MAAM,UAAU,GAAG,KAAK;CACxB,QAAQ,YAAY;CACpB,IAAI,SAAS;EACZ,SAAS;EACT,qBAAqB,oBAAoB,OAAO;EAChD,QAAQ,GAAG,WAAW;EACtB,YAAY;EACZ,aAAa;EACb,YAAY,WAAW,8BAA8B;EACrD,cAAc;EACd,QAAQ;EACR,WAAW;CACZ,CAAC;CACD,QAAQ,WAAW;CACnB,QAAQ,aAAa,QAAQ,KAAK;CAClC,QAAQ,aAAa,iBAAiB,OAAO,QAAQ,CAAC;CACtD,QAAQ,QAAQ,YAAY,OAAO,IAAI,EAAE;CACzC,QAAQ,iBAAiB,eAAe;EACvC,MAAM,OAAOA,SAAO,GAAG;EACvB,IAAI,WAAW;GAAC,IAAI,IAAI;GAAI;EAAI,CAAC;CAClC,CAAC;CACD,QAAQ,iBAAiB,YAAY,UAAU;EAC9C,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;GAC/C,MAAM,eAAe;GACrB,IAAI,YAAY,IAAI,EAAE;EACvB;CACD,CAAC;CAED,KAAK,MAAM,UAAU,eAAe,OAAO,GAC1C,QAAQ,OAAO,UAAU,QAAQ,KAAK,aAAa,KAAK,QAAQ,iBAAiB,CAAC;CAGnF,OAAO;AACR;;;;;;;;;;AAWA,SAAgB,eAAe,WAAwB,OAAmB,KAAwB,SAAuB,oBAAoB,MAAY;CACxJ,MAAM,EAAC,SAAS,YAAY,aAAa,YAAY,UAAU,YAAY,eAAe,WAAU;CAEpG,MAAM,OAAO,SAAS,uBAAuB;CAE7C,IAAI,aAAa,GAAG;EACnB,MAAM,SAAS,GAAG,KAAK;EACvB,OAAO,MAAM,SAAS,GAAG,WAAW;EACpC,KAAK,OAAO,MAAM;CACnB;CAEA,KAAK,MAAM,OAAO,QAAQ,MAAM,YAAY,WAAW,CAAC,GACvD,KAAK,OAAO,SAAS,KAAK,YAAY,aAAa,KAAK,SAAS,QAAQ,iBAAiB,CAAC;CAG5F,IAAI,gBAAgB,GAAG;EACtB,MAAM,SAAS,GAAG,KAAK;EACvB,OAAO,MAAM,SAAS,GAAG,cAAc;EACvC,KAAK,OAAO,MAAM;CACnB;CAEA,cAAc,SAAS;CACvB,UAAU,OAAO,IAAI;AACtB;;;;;;;;AASA,SAAgB,oBAAoB,SAAuB,QAAkC;CAC5F,MAAM,SAAS,GAAG,KAAK;CACvB,IAAI,QAAQ;EACX,SAAS;EACT,qBAAqB,oBAAoB,OAAO;EAChD,QAAQ;EACR,YAAY;EACZ,cAAc;EACd,aAAa;EACb,YAAY;EACZ,eAAe;EACf,WAAW;CACZ,CAAC;CAED,MAAM,UAAU,eAAe,OAAO;CACtC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACxC,MAAM,SAAS,QAAQ;EACvB,IAAI,WAAW,KAAA,GACd;EAED,MAAM,UAAU,GAAG,KAAK;EACxB,IAAI,SAAS;GAAC,UAAU;GAAY,SAAS;GAAQ,YAAY;EAAU,CAAC;EAE5E,IAAI,MAAM,KAAK,QAAQ,IAAI,OAAO,QAAQ;GACzC,MAAM,eAAe,GAAG,KAAK;GAC7B,aAAa,YAAY;GACzB,IAAI,cAAc;IACjB,SAAS;IACT,KAAK;IACL,aAAa;IACb,eAAe;GAChB,CAAC;GAED,MAAM,YAAY,GAAG,QAAQ;GAC7B,UAAU,YAAY;GACtB,UAAU,cAAc;GACxB,UAAU,QAAQ,OAAO,QAAQ,kBAAkB,aAAa;GAChE,UAAU,aAAa,cAAc,UAAU,KAAK;GACpD,IAAI,WAAW;IACd,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,YAAY;IACZ,QAAQ;IACR,cAAc;IACd,QAAQ;IACR,OAAO;IACP,UAAU;IACV,YAAY;IACZ,YAAY;IACZ,SAAS;GACV,CAAC;GAED,MAAM,cAAc,GAAG,QAAQ;GAC/B,YAAY,YAAY;GACxB,YAAY,cAAc;GAC1B,YAAY,QAAQ,OAAO,QAAQ,oBAAoB,aAAa;GACpE,YAAY,aAAa,cAAc,YAAY,KAAK;GACxD,IAAI,aAAa;IAChB,OAAO;IACP,QAAQ;IACR,SAAS;IACT,YAAY;IACZ,gBAAgB;IAChB,YAAY;IACZ,QAAQ;IACR,cAAc;IACd,QAAQ;IACR,OAAO;IACP,UAAU;IACV,YAAY;IACZ,YAAY;IACZ,SAAS;GACV,CAAC;GAED,aAAa,OAAO,WAAW,WAAW;GAC1C,QAAQ,OAAO,YAAY;EAC5B;EAEA,MAAM,OAAO,GAAG,MAAM;EACtB,IAAI,MAAM;GACT,UAAU;GACV,YAAY;GACZ,OAAO;GACP,eAAe;GACf,eAAe;GACf,cAAc;EACf,CAAC;EACD,IAAI,OAAO,UAAU,KAAA,GACpB,KAAK,MAAM,YAAY,OAAO;EAE/B,KAAK,cAAc,OAAO;EAC1B,QAAQ,OAAO,IAAI;EAEnB,IAAI,IAAI,QAAQ,SAAS,GAAG;GAC3B,MAAM,SAAS,GAAG,KAAK;GACvB,OAAO,YAAY;GACnB,IAAI,QAAQ;IACX,UAAU;IACV,OAAO;IACP,KAAK;IACL,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,QAAQ;GACT,CAAC;GACD,QAAQ,OAAO,MAAM;EACtB;EAEA,OAAO,OAAO,OAAO;CACtB;CAEA,OAAO;AACR;;;;;;;;;;;AAcA,SAAgB,kBAAkB,UAAuB,QAAqB,SAAuB,UAAwD;CAC5J,MAAM,UAAU,SAAS,iBAA8B,0BAA0B;CACjF,MAAM,WAA2B,CAAC;CAElC,KAAK,IAAI,WAAW,GAAG,WAAW,QAAQ,QAAQ,YAAY;EAC7D,MAAM,SAAS,QAAQ,KAAK,QAAQ;EACpC,IAAI,WAAW,MACd;EAED,MAAM,mBAAmB;EAEzB,MAAM,iBAAiB,MAA0B;GAChD,IAAI,EAAE,WAAW,GAChB;GAED,EAAE,eAAe;GACjB,EAAE,gBAAgB;GAElB,MAAM,SAAS,EAAE;GAEjB,MAAM,cAAc,CADL,GAAG,SAAS,QACH,EAAE,KAAK,MAAM,EAAE,sBAAsB,EAAE,KAAK;GAEpE,MAAM,UAAU,OAA2B;IAC1C,MAAM,KAAK,GAAG,UAAU;IACxB,MAAM,YAAY,CAAC,GAAG,WAAW;IAEjC,UAAU,oBAAoB,KAAK,IAAI,mBAAmB,YAAY,qBAAqB,KAAK,EAAE;IAElG,IAAI,mBAAmB,IAAI,UAAU,QACpC,UAAU,mBAAmB,KAAK,KAAK,IAAI,mBAAmB,YAAY,mBAAmB,MAAM,KAAK,EAAE;IAG3G,MAAM,WAAW,UAAU,KAAK,MAAM,GAAG,KAAK,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,GAAG;IACpE,SAAS,MAAM,sBAAsB;IAErC,MAAM,OAAO,OAAO,iBAA8B,gBAAc;IAChE,KAAK,MAAM,OAAO,MACjB,IAAI,MAAM,sBAAsB;GAElC;GAEA,MAAM,aAAmB;IACxB,OAAO,oBAAoB,eAAe,MAAM;IAChD,OAAO,oBAAoB,aAAa,IAAI;IAE5C,MAAM,aAAa,CAAC,GAAG,SAAS,QAAQ;IACxC,MAAM,UAAU,eAAe,OAAO;IACtC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,UAAU,IAAI,WAAW,QAAQ,KAAK;KACjE,MAAM,MAAM,QAAQ;KACpB,MAAM,OAAO,WAAW;KACxB,IAAI,QAAQ,KAAA,KAAa,SAAS,KAAA,GAAW;MAC5C,MAAM,IAAI,KAAK,sBAAsB,EAAE;MACvC,IAAI,QAAQ,GAAG,KAAK,MAAM,CAAC,EAAE;KAC9B;IACD;IACA,WAAW,CAAC,GAAG,OAAO,CAAC;GACxB;GAEA,OAAO,iBAAiB,eAAe,MAAM;GAC7C,OAAO,iBAAiB,aAAa,IAAI;EAC1C;EAEA,OAAO,iBAAiB,eAAe,aAAa;EACpD,SAAS,WAAW;GACnB,OAAO,oBAAoB,eAAe,aAAa;EACxD,CAAC;CACF;CAEA,aAAa;EACZ,KAAK,MAAM,WAAW,UACrB,QAAQ;CAEV;AACD;;;AC9eA,MAAM,KAAK;AACX,MAAM,aAAa;AACnB,MAAM,aAAa;;;;;;;;;;;AAiBnB,SAAgB,sBAAsB,aAAqB,cAAqC;CAC/F,MAAM,MAAM,SAAS,gBAAgB,IAAI,KAAK;CAC9C,OAAO,OAAO,IAAI,OAAO;EACxB,UAAU;EACV,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,QAAQ;CACT,CAAC;CAGD,MAAM,OAAO,SAAS,gBAAgB,IAAI,MAAM;CAEhD,KAAK,MAAM,CAAC,IAAI,UAAU,CACzB,CAAC,eAAe,mBAAmB,GACnC,CAAC,kBAAkB,sBAAsB,CAC1C,GAAY;EACX,MAAM,SAAS,SAAS,gBAAgB,IAAI,QAAQ;EACpD,SAAS,QAAQ;GAChB;GACA,SAAS;GACT,MAAM;GACN,MAAM;GACN,aAAa;GACb,cAAc;GACd,QAAQ;EACT,CAAC;EACD,MAAM,OAAO,SAAS,gBAAgB,IAAI,MAAM;EAChD,SAAS,MAAM;GAAC,GAAG;GAAY,MAAM;EAAK,CAAC;EAC3C,OAAO,OAAO,IAAI;EAClB,KAAK,OAAO,MAAM;CACnB;CAEA,IAAI,OAAO,IAAI;CAGf,MAAM,YAAY,SAAS,gBAAgB,IAAI,MAAM;CACrD,SAAS,WAAW;EACnB,GAAG;EACH,MAAM;EACN,QAAQ;EACR,gBAAgB;EAChB,oBAAoB;CACrB,CAAC;CACD,UAAU,UAAU,IAAI,kBAAkB;CAC1C,UAAU,MAAM,UAAU;CAC1B,IAAI,OAAO,SAAS;CAEpB,OAAO;AACR;;;;;;;;;;;AAYA,SAAgB,cAAc,KAAoB,IAAY,IAAY,IAAY,IAAY,OAAsB;CACvH,MAAM,QAAQ,IAAI,cAA8B,uBAAuB;CACvE,IAAI,UAAU,MACb;CAED,SAAS,OAAO,EACf,GAAG,KAAK,GAAG,GAAG,GAAG,KAAK,GAAG,GAAG,KAC7B,CAAC;CACD,IAAI,OACH,MAAM,gBAAgB,kBAAkB;MAExC,MAAM,aAAa,oBAAoB,KAAK;CAE7C,IAAI,OACH,MAAM,aAAa,cAAc,mBAAmB;MAEpD,MAAM,gBAAgB,YAAY;CAEnC,MAAM,MAAM,UAAU;AACvB;;;;;;AAOA,SAAgB,cAAc,KAA0B;CACvD,MAAM,QAAQ,IAAI,cAA8B,uBAAuB;CACvE,IAAI,UAAU,MAAM;EACnB,MAAM,MAAM,UAAU;EACtB,MAAM,gBAAgB,YAAY;CACnC;AACD;;;;;;;;;;;;;AAcA,SAAgB,sBACf,KACA,OACA,YACA,aACA,gBACA,qCACA,KACO;CACP,SAAS,KAAK;EAAC,OAAO;EAAY,QAAQ;CAAW,CAAC;CAEtD,MAAM,WAAW,CAAC,GAAG,IAAI,QAAQ,EAAE,MAAM,CAAC,EAAE,QAAQ,MAAM,CAAC,EAAE,UAAU,SAAS,kBAAkB,CAAC;CACnG,KAAK,MAAM,QAAQ,UAClB,IAAI,YAAY,IAAI;CAGrB,MAAM,QAAQ,IAAI,cAA8B,uBAAuB;CAEvE,KAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,EAAC,WAAU;EACjB,IAAI,OAAO,WAAW,GACrB;EAGD,MAAM,CAAC,OAAO,GAAG,QAAQ;EACzB,MAAM,IAAI,KAAK,MAAM,EAAE,GAAG,MAAM,IAAI,KAAK,KAAK,MAAM,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;EAE/E,MAAM,YACL,uCAAuC,mBAAmB,SAAS,KAAK,iBAAiB,kBAAkB,KAAK,iBAAiB;EAElI,MAAM,OAAO,SAAS,gBAAgB,IAAI,MAAM;EAChD,SAAS,MAAM;GACd;GACA,MAAM;GACN,QAAQ,YAAY,yBAAyB;GAC7C,gBAAgB,YAAY,QAAQ;GACpC,mBAAmB;GACnB,cAAc,YAAY,yBAAyB;GACnD,gBAAgB,OAAO,KAAK,MAAM;EACnC,CAAC;EACD,KAAK,MAAM,gBAAgB;EAC3B,KAAK,MAAM,SAAS;EAEpB,KAAK,iBAAiB,UAAU,UAAU;GACzC,IAAI,MAAM,WAAW,GACpB,KAAK,cAAc;IAClB,IAAI,KAAK;IACT,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,MAAM,KAAK;GACZ,CAAC;EAEH,CAAC;EACD,KAAK,iBAAiB,aAAa,WAAW;GAC7C,KAAK,iBAAiB;IACrB,IAAI,KAAK;IACT,QAAQ,KAAK;IACb,QAAQ,KAAK;IACb,MAAM,KAAK;GACZ,CAAC;EACF,CAAC;EAED,IAAI,UAAU,MACb,IAAI,aAAa,MAAM,KAAK;OAE5B,IAAI,OAAO,IAAI;CAEjB;AACD;;;ACtLA,SAAgB,OAAO,MAAsB;CAC5C,MAAM,OAAO;EACZ,IAAI,KAAK;EACT,MAAM,KAAK;EACX,WAAW,KAAK;EAChB,GAAI,KAAK,WAAW,KAAA,IAAY,CAAC,IAAI,EAAC,QAAQ,KAAK,OAAM;EACzD,GAAI,KAAK,UAAU,KAAA,IAAY,CAAC,IAAI,EAAC,OAAO,KAAK,MAAK;EACtD,GAAI,KAAK,aAAa,KAAA,IAAY,CAAC,IAAI,EAAC,UAAU,KAAK,SAAQ;EAC/D,GAAI,KAAK,SAAS,KAAA,IAAY,CAAC,IAAI,EAAC,MAAM,KAAK,KAAI;CACpD;CAEA,QAAQ,KAAK,MAAb;EACC,KAAK,QACJ,OAAO;GACN,GAAG;GACH,MAAM;GACN,SAAS,KAAK;GACd,iBAAiB,KAAK;EACvB;EAED,KAAK,WACJ,OAAO;GACN,GAAG;GACH,MAAM;GACN,SAAS,KAAK;GACd,iBAAiB,KAAK;GACtB,MAAM,KAAK;EACZ;EAED,KAAK,aACJ,OAAO;GAAC,GAAG;GAAM,MAAM;EAAW;CAEpC;AACD;;;;;;;;;;;;;;AAeA,SAAgB,WAAW,OAAoB,gBAA6B,MAAgB,WAA8B,KAAoC;CAC7J,SAAS,UAAU,GAAuB;EACzC,IAAI,EAAE,WAAW,GAChB;EAED,EAAE,eAAe;EACjB,IAAI;GACH,MAAM,kBAAkB,EAAE,SAAS;EACpC,QAAQ,CAER;EACA,IAAI,cAAc,KAAK,EAAE;EAEzB,MAAM,SAAS,EAAE;EACjB,MAAM,aAAa,UAAU,KAAK,SAAS;EAC3C,MAAM,SAAS,UAAU;EAEzB,IAAI,WAAW;EAEf,SAAS,OAAO,IAAwB;GACvC,MAAM,KAAK,GAAG,UAAU;GACxB,WAAW,KAAK,MAAM,OAAO,oBAAoB,EAAE,CAAC;GACpD,IAAI,aAAa;IAAC,IAAI,KAAK;IAAI,WAAW,QAAQ,YAAY,QAAQ;GAAC,CAAC;EACzE;EAEA,SAAS,OAAa;GACrB,OAAO,oBAAoB,eAAe,MAAM;GAChD,OAAO,oBAAoB,aAAa,IAAI;GAC5C,MAAM,MAAM,SAAS;GACrB,IAAI,aAAa,GAChB,IAAS,mBAAmB;IAAC,IAAI,KAAK;IAAI,WAAW,QAAQ,YAAY,QAAQ;GAAC,CAAC;EAErF;EAEA,MAAM,MAAM,SAAS;EACrB,OAAO,iBAAiB,eAAe,MAAM;EAC7C,OAAO,iBAAiB,aAAa,IAAI;CAC1C;CAEA,SAAS,aAAa,GAAuB;EAC5C,IAAI,EAAE,WAAW,GAChB;EAED,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,IAAI;GACH,eAAe,kBAAkB,EAAE,SAAS;EAC7C,QAAQ,CAER;EAEA,MAAM,SAAS,EAAE;EACjB,IAAI,KAAK,SAAS,aACjB;EAED,MAAM,UAAU,UAAU,KAAK,OAAO;EACtC,MAAM,SAAS,UAAU;EAEzB,IAAI,UAAU;EAEd,SAAS,OAAO,IAAwB;GACvC,MAAM,KAAK,GAAG,UAAU;GAExB,UAAU,QAAQ,SADA,KAAK,MAAM,OAAO,oBAAoB,EAAE,CACvB,CAAC;GACpC,IAAI,eAAe;IAAC,IAAI,KAAK;IAAI,SAAS,QAAQ,YAAY,EAAE,MAAM,GAAG,EAAE;GAAC,CAAC;EAC9E;EAEA,SAAS,OAAa;GACrB,OAAO,oBAAoB,eAAe,MAAM;GAChD,OAAO,oBAAoB,aAAa,IAAI;GAC5C,IAAS,qBAAqB;IAAC,IAAI,KAAK;IAAI,SAAS,QAAQ,YAAY,EAAE,MAAM,GAAG,EAAE;GAAC,CAAC;EACzF;EAEA,OAAO,iBAAiB,eAAe,MAAM;EAC7C,OAAO,iBAAiB,aAAa,IAAI;CAC1C;CAEA,MAAM,iBAAiB,eAAe,SAAS;CAC/C,eAAe,iBAAiB,eAAe,YAAY;CAE3D,aAAa;EACZ,MAAM,oBAAoB,eAAe,SAAS;EAClD,eAAe,oBAAoB,eAAe,YAAY;CAC/D;AACD;;;;;;;;;;;AAYA,SAAgB,mBACf,YACA,OACA,MACA,YACA,KACa;CACb,SAAS,eAAe,GAAuB;EAC9C,IAAI,EAAE,WAAW,GAChB;EAED,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,IAAI,cAAc,KAAK,EAAE;EACzB,IAAI;GACH,WAAW,kBAAkB,EAAE,SAAS;EACzC,QAAQ,CAER;EAEA,MAAM,SAAS,EAAE;EACjB,MAAM,WAAW,MAAM,sBAAsB,EAAE;EAC/C,MAAM,cAAc,KAAK,SAAS,cAAe,KAAK,mBAAmB,IAAK;EAE9E,IAAI,cAAc;EAElB,SAAS,OAAO,IAAwB;GACvC,MAAM,KAAK,GAAG,UAAU;GACxB,MAAM,eAAe,WAAW,IAAK,KAAK,WAAY,MAAM;GAC5D,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,cAAc,YAAY,CAAC,CAAC;GAC/E,IAAI,qBAAqB;IAAC,IAAI,KAAK;IAAI,iBAAiB;GAAW,CAAC;EACrE;EAEA,SAAS,OAAa;GACrB,OAAO,oBAAoB,eAAe,MAAM;GAChD,OAAO,oBAAoB,aAAa,IAAI;GAC5C,WAAW,MAAM,SAAS;GAC1B,IAAS,2BAA2B;IAAC,IAAI,KAAK;IAAI,iBAAiB;GAAW,CAAC;EAChF;EAEA,WAAW,MAAM,SAAS;EAC1B,OAAO,iBAAiB,eAAe,MAAM;EAC7C,OAAO,iBAAiB,aAAa,IAAI;CAC1C;CAEA,WAAW,iBAAiB,eAAe,cAAc;CAEzD,aAAa;EACZ,WAAW,oBAAoB,eAAe,cAAc;CAC7D;AACD;;;;;;;;;AAUA,SAAgB,qBAAqB,WAAwB,QAAgB,KAAoC;CAChH,SAAS,UAAgB;EACxB,IAAI,cAAc,MAAM;CACzB;CACA,SAAS,cAAc,OAAyB;EAC/C,IAAI,MAAM,WAAW,GAAG;GACvB,MAAM,OAAQ,UAA4C;GAC1D,IAAI,SAAS,KAAA,GACZ;GAED,IAAI,oBAAoB;IAAC,IAAI;IAAQ;GAAI,CAAC;EAC3C;CACD;CACA,UAAU,iBAAiB,SAAS,OAAO;CAC3C,UAAU,iBAAiB,SAAS,aAAa;CACjD,aAAa;EACZ,UAAU,oBAAoB,SAAS,OAAO;EAC9C,UAAU,oBAAoB,SAAS,aAAa;CACrD;AACD;AAEA,SAAgB,kBAAkB,WAAwB,MAAkB;CAC3E,UAA6C,SAAS;AACvD;;;;;;;;;;;;;;;ACjOA,SAAgB,yBACf,QACA,cACA,SACA,SACA,UACA,eACA,KACa;CACb,SAAS,cAAc,GAAuB;EAC7C,IAAI,EAAE,WAAW,GAChB;EAED,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAClB,IAAI;GACH,OAAO,kBAAkB,EAAE,SAAS;EACrC,QAAQ,CAER;EAEA,IAAI,gBAA+B;EAEnC,SAAS,OAAO,IAAwB;GACvC,MAAM,YAAY,cAAc,sBAAsB;GACtD,MAAM,IAAI,GAAG,UAAU,UAAU;GACjC,MAAM,IAAI,GAAG,UAAU,UAAU;GAIjC,MAAM,QADK,SAAS,iBAAiB,GAAG,SAAS,GAAG,OACrC,GAAG,QAAqB,gBAAgB;GACvD,MAAM,WAAW,UAAU,QAAQ,UAAU,KAAA,IAAY,OAAO,MAAM,QAAQ,SAAS,IAAI;GAE3F,gBAAgB,aAAa,QAAQ,aAAa,eAAe,WAAW;GAE5E,cAAc,UAAU,SAAS,SAAS,GAAG,GAAG,kBAAkB,IAAI;EACvE;EAEA,SAAS,OAAa;GACrB,OAAO,oBAAoB,eAAe,MAAM;GAChD,OAAO,oBAAoB,aAAa,IAAI;GAC5C,cAAc,QAAQ;GAEtB,IAAI,kBAAkB,MACrB,IAAI,eAAe;IAAC;IAAc,cAAc;IAAe,MAAM;GAAI,CAAC;EAE5E;EAEA,OAAO,iBAAiB,eAAe,MAAM;EAC7C,OAAO,iBAAiB,aAAa,IAAI;CAC1C;CAEA,OAAO,iBAAiB,eAAe,aAAa;CACpD,OAAO,WAAW;CAClB,OAAO,aAAa,QAAQ,QAAQ;CACpC,OAAO,aAAa,cAAc,yBAAyB,cAAc;CAEzE,SAAS,UAAU,OAA4B;EAC9C,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAC1C,MAAM,eAAe;CAEvB;CACA,OAAO,iBAAiB,WAAW,SAAS;CAE5C,aAAa;EACZ,OAAO,oBAAoB,eAAe,aAAa;EACvD,OAAO,oBAAoB,WAAW,SAAS;CAChD;AACD;;;;;;;AAQA,SAAgB,uBAAoC;CACnD,MAAM,SAAS,SAAS,cAAc,KAAK;CAC3C,OAAO,YAAY;CACnB,OAAO,MAAM,WAAW;CACxB,OAAO,MAAM,QAAQ;CACrB,OAAO,MAAM,SAAS;CACtB,OAAO,MAAM,eAAe;CAC5B,OAAO,MAAM,aAAa;CAC1B,OAAO,MAAM,SAAS;CACtB,OAAO,MAAM,SAAS;CACtB,OAAO,MAAM,SAAS;CACtB,OAAO,MAAM,UAAU;CACvB,OAAO,MAAM,aAAa;CAC1B,OAAO,MAAM,YAAY;CACzB,OAAO,MAAM,gBAAgB;CAC7B,OAAO,MAAM,cAAc;CAC3B,OAAO;AACR;;;AClFA,MAAM,YAAoC;CACzC,MAAM;CACN,SAAS;CACT,WAAW;AACZ;;;;;;AA+BA,SAAgB,sBAAqC;CACpD,MAAM,kBAAkB,GAAG,KAAK;CAChC,MAAM,kBAAkB,GAAG,KAAK;CAChC,MAAM,gBAAgB,GAAG,KAAK;CAC9B,MAAM,WAAW,sBAAsB,GAAG,CAAC;CAE3C,IAAI,iBAAiB,EAAC,UAAU,WAAU,CAAC;CAC3C,IAAI,eAAe;EAAC,UAAU;EAAY,KAAK;EAAQ,MAAM;CAAG,CAAC;CAEjE,gBAAgB,OAAO,eAAe;CACtC,gBAAgB,OAAO,aAAa;CACpC,cAAc,OAAO,QAAQ;CAE7B,MAAM,YAAY,GAAG,KAAK;CAC1B,UAAU,YAAY;CACtB,UAAU,MAAM,UAAU;CAC1B,gBAAgB,OAAO,SAAS;CAEhC,OAAO;EACN;EACA;EACA;EACA;EACA;EACA,6BAAa,IAAI,IAAI;CACtB;AACD;AAEA,SAAS,UAAU,QAAqB,KAAmC,KAAqB;CAE/F,OAAO,YADU,OAAO,SAAS,QAAQ,aAAa,MACzB,GAAG;AACjC;AAEA,SAAS,4BAA4B,OAAoB,YAAqB,OAAmB,eAA6B;CAC7H,MAAM,EAAC,QAAQ,eAAe,aAAa,cAAc,aAAa,sBAAqB;CAC3F,IAAI,MAAM,WAAW,aAAa;CAElC,OAAO,MAAM,aAAa;EACzB,MAAM,OAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAU;EAChD,MAAM,IAAI,OAAO,IAAI,GAAG;EACxB,MAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,IAAI,IAAI,CAAC;EAC9C,MAAM,UAAU,IAAI,YAAY,EAAE,MAAM,GAAG,EAAE;EAC7C,MAAM,aAAa,kBAAkB,IAAI,OAAO;EAChD,MAAM,YAAY,YAAY,IAAI,IAAI,UAAU,CAAC;EAEjD,IAAI,OAAgD;EACpD,IAAI,eAAe,KAAA,GAAW;GAC7B,MAAM,EAAC,MAAM,gBAAe;GAC5B,OAAO;EACR,OAAO,IAAI,gBAAgB,WAC1B,OAAO;EAGR,IAAI,SAAS,MAAM;GAClB,MAAM,UAAU,GAAG,KAAK;GACxB,QAAQ,YAAY,kCAAkC;GACtD,IAAI,YAAY,cAAc,KAAA,GAC7B,QAAQ,UAAU,IAAI,WAAW,SAAS;GAE3C,QAAQ,QAAQ,UAAU;GAC1B,IAAI,YAAY,UAAU,KAAA,GAAW;IACpC,QAAQ,QAAQ,WAAW,WAAW;IACtC,QAAQ,QAAQ,WAAW;GAC5B;GACA,IAAI,SAAS;IACZ,UAAU;IACV,MAAM,GAAG,EAAE;IACX,KAAK;IACL,OAAO,GAAG,MAAM;IAChB,QAAQ,GAAG,cAAc;IACzB,eAAe;IACf,QAAQ;GACT,CAAC;GACD,MAAM,aAAa,SAAS,UAAU;EACvC;EAEA,MAAM;CACP;AACD;AAIA,SAAS,UACR,OACA,UACA,MACA,QACA,YACA,UACA,OACA,KACA,WACO;CACP,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,WAAW,KAAK,aAAa;CACnC,MAAM,QAAQ,UAAU,OAAO,SAAS,UAAU;CAElD,MAAM,MAAM,GAAG,KAAK;CACpB,IAAI,YAAY,YAAY,WAAW,+CAA+C;CACtF,IAAI,KAAK;EACR,UAAU;EACV,MAAM,GAAG,OAAO,EAAE;EAClB,KAAK,GAAG,OAAO,EAAE;EACjB,OAAO,GAAG,OAAO,MAAM;EACvB,QAAQ,GAAG,OAAO,OAAO;EACzB,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAC,YAAY,MAAK;EACjD,cAAc,OAAO,SAAS,YAAY,QAAQ;EAClD,QAAQ,WAAW,YAAY;EAC/B,YAAY;EACZ,UAAU;EACV,QAAQ,WAAW,MAAM;EACzB,aAAa;CACd,CAAC;CAGD,IAAI;CACJ,IAAI,OAAO,gBAAgB,GAAG;EAC7B,MAAM,OAAO,GAAG,KAAK;EACrB,MAAM,kBAAkB,MAAM;EAC9B,IAAI,MAAM;GACT,UAAU;GACV,MAAM;GACN,KAAK;GACL,OAAO,GAAG,OAAO,cAAc;GAC/B,QAAQ;GACR,YAAY;GACZ,GAAI,kBAAkB;IAAC,QAAQ;IAAa,aAAa;GAAM,IAAI,EAAC,eAAe,OAAM;EAC1F,CAAC;EACD,IAAI,iBAAiB;GACpB,KAAK,YAAY;GACjB,sBAAsB,mBAAmB,MAAM,KAAK,YAAY,MAAM,QAAQ,GAAG;EAClF;EACA,IAAI,OAAO,IAAI;CAChB;CAGA,MAAM,QAAQ,GAAG,MAAM;CACvB,IAAI,OAAO;EACV,UAAU;EACV,MAAM;EACN,OAAO;EACP,KAAK;EACL,WAAW;EACX,UAAU;EACV,cAAc;EACd,OAAO;EACP,UAAU;EACV,YAAY;EACZ,YAAY;EACZ,eAAe;EACf,YAAY;CACb,CAAC;CACD,MAAM,cAAc,KAAK;CACzB,IAAI,OAAO,KAAK;CAChB,IAAI,WAAW;CACf,IAAI,aAAa,QAAQ,QAAQ;CACjC,IAAI,aAAa,cAAc,UAAU,MAAM,QAAQ,YAAY,KAAK,IAAI,CAAC;CAC7E,IAAI,aAAa,gBAAgB,OAAO,QAAQ,CAAC;CACjD,IAAI,QAAQ,YAAY,OAAO,KAAK,EAAE;CACtC,IAAI,iBAAiB,UAAU,UAAU;EACxC,IAAI,MAAM,WAAW,GACpB,IAAI,oBAAoB;GAAC,IAAI,KAAK;GAAI,MAAM,OAAO,IAAI;EAAC,CAAC;OAEzD,IAAI,cAAc,KAAK,EAAE;CAE3B,CAAC;CACD,IAAI,iBAAiB,YAAY,UAAU;EAC1C,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;GAC/C,MAAM,eAAe;GACrB,IAAI,cAAc,KAAK,EAAE;EAC1B;CACD,CAAC;CAED,IAAI;CACJ,IAAI;CAEJ,IAAI,CAAC,UAAU;EAEd,SAAS,GAAG,KAAK;EACjB,OAAO,YAAY;EACnB,IAAI,QAAQ;GACX,UAAU;GACV,OAAO;GACP,KAAK;GACL,OAAO;GACP,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,aAAa;EACd,CAAC;EACD,IAAI,OAAO,MAAM;EAEjB,MAAM,aAAa,KAAK,QAAQ;EAChC,cAAc,WAAW,KAAK,QAAQ,YAAY,MAAM,QAAQ,GAAG;CACpE,OACC,MAAM,aAAa,KAAK,QAAQ;CAIjC,IAAI;CACJ,IAAI,MAAM,qBAAqB;EAC9B,MAAM,aAAa,OAAO,IAAI,OAAO,SAAS;EAC9C,MAAM,aAAa,qBAAqB;EACxC,WAAW,MAAM,OAAO,GAAG,OAAO,EAAE;EACpC,WAAW,MAAM,MAAM,GAAG,WAAW;EACrC,MAAM,aAAa,YAAY,QAAQ;EAEvC,MAAM,cAAc,qBAAqB;EACzC,YAAY,MAAM,OAAO,GAAG,OAAO,IAAI,OAAO,MAAM;EACpD,YAAY,MAAM,MAAM,GAAG,WAAW;EACtC,MAAM,aAAa,aAAa,QAAQ;EAExC,MAAM,cAAc,yBAAyB,YAAY,KAAK,IAAI,OAAO,GAAG,YAAY,UAAU,OAAO,GAAG;EAC5G,MAAM,eAAe,yBAAyB,aAAa,KAAK,IAAI,OAAO,IAAI,OAAO,OAAO,YAAY,UAAU,OAAO,GAAG;EAG7H,MAAM,mBAAyB;GAC9B,WAAW,MAAM,UAAU;GAC3B,YAAY,MAAM,UAAU;GAC5B,WAAW,MAAM,YAAY;GAC7B,YAAY,MAAM,YAAY;EAC/B;EACA,MAAM,mBAAyB;GAC9B,WAAW,MAAM,UAAU;GAC3B,YAAY,MAAM,UAAU;GAC5B,WAAW,MAAM,YAAY;GAC7B,YAAY,MAAM,YAAY;EAC/B;EACA,IAAI,iBAAiB,cAAc,UAAU;EAC7C,IAAI,iBAAiB,cAAc,UAAU;EAE7C,2BAAiC;GAChC,YAAY;GACZ,aAAa;GACb,IAAI,oBAAoB,cAAc,UAAU;GAChD,IAAI,oBAAoB,cAAc,UAAU;EACjD;CACD;CAGA,MAAM,uBAA6B;EAClC,MAAM,UAAU,IAAI,gBAAgB;GAAC,IAAI,KAAK;GAAI,MAAM,OAAO,IAAI;EAAC,CAAC;EACrE,IAAI,WAAW,QAAQ,SAAS,GAAG;GAClC,UAAU,YAAY;GACtB,UAAU,MAAM,UAAU;EAC3B,OACC,UAAU,MAAM,UAAU;CAE5B;CACA,MAAM,iBAAiB,MAAwB;EAC9C,MAAM,UAAU;EAChB,MAAM,UAAU;EAChB,IAAI,OAAO,EAAE,UAAU;EACvB,IAAI,MAAM,EAAE,UAAU;EACtB,MAAM,UAAU,OAAO,aAAa,UAAU,cAAc;EAC5D,MAAM,SAAS,OAAO,cAAc,UAAU,eAAe;EAC7D,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,OAAO,CAAC;EAC1C,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,CAAC;EACvC,UAAU,MAAM,OAAO,GAAG,KAAK;EAC/B,UAAU,MAAM,MAAM,GAAG,IAAI;CAC9B;CACA,MAAM,uBAA6B;EAClC,UAAU,MAAM,UAAU;CAC3B;CACA,IAAI,iBAAiB,cAAc,cAAc;CACjD,IAAI,iBAAiB,aAAa,aAAa;CAC/C,IAAI,iBAAiB,cAAc,cAAc;CACjD,MAAM,uBAA6B;EAClC,IAAI,oBAAoB,cAAc,cAAc;EACpD,IAAI,oBAAoB,aAAa,aAAa;EAClD,IAAI,oBAAoB,cAAc,cAAc;CACrD;CAEA,MAAM,QAOF;EAAC;EAAK,cAAc,UAAU,GAAG,KAAK;CAAC;CAC3C,IAAI,gBAAgB,KAAA,GACnB,MAAM,cAAc;CAErB,IAAI,uBAAuB,KAAA,GAC1B,MAAM,qBAAqB;CAE5B,IAAI,wBAAwB,KAAA,GAC3B,MAAM,sBAAsB;CAE7B,IAAI,mBAAmB,KAAA,GACtB,MAAM,iBAAiB;CAExB,SAAS,IAAI,KAAK,IAAI,KAAK;AAC5B;AAIA,SAAS,gBACR,OACA,UACA,MACA,QACA,YACA,UACA,KACA,OACA,WACO;CACP,MAAM,WAAW,KAAK,OAAO;CAC7B,MAAM,WAAW,KAAK,aAAa;CACnC,MAAM,OAAO,iBAAiB;CAE9B,MAAM,UAAU,GAAG,KAAK;CACxB,QAAQ,YAAY,kBAAkB,WAAW,2BAA2B;CAC5E,IAAI,SAAS;EACZ,UAAU;EACV,MAAM,GAAG,OAAO,IAAI,eAAe;EACnC,KAAK,GAAG,OAAO,KAAK,OAAO,SAAS,QAAQ,EAAE;EAC9C,OAAO,GAAG,KAAK;EACf,QAAQ,GAAG,KAAK;EAChB,YAAY;EACZ,WAAW;EACX,QAAQ,WAAW,YAAY;EAC/B,QAAQ;CACT,CAAC;CACD,QAAQ,WAAW;CACnB,QAAQ,aAAa,QAAQ,QAAQ;CACrC,QAAQ,aAAa,cAAc,UAAU,MAAM,QAAQ,iBAAiB,KAAK,IAAI,CAAC;CACtF,QAAQ,aAAa,gBAAgB,OAAO,QAAQ,CAAC;CACrD,QAAQ,QAAQ,YAAY,OAAO,KAAK,EAAE;CAC1C,QAAQ,iBAAiB,YAAY,UAAU;EAC9C,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;GAC/C,MAAM,eAAe;GACrB,IAAI,cAAc,KAAK,EAAE;EAC1B;CACD,CAAC;CACD,MAAM,UAAU,GAAG,MAAM;CACzB,IAAI,SAAS;EACZ,UAAU;EACV,MAAM;EACN,KAAK;EACL,WAAW;EACX,UAAU;EACV,YAAY;EACZ,OAAO;EACP,YAAY;EACZ,eAAe;CAChB,CAAC;CACD,QAAQ,cAAc,KAAK;CAC3B,QAAQ,OAAO,OAAO;CAEtB,MAAM,aAAa,SAAS,QAAQ;CACpC,kBAAkB,SAAS,IAAI;CAG/B,MAAM,QAAQ,GAAG,KAAK;CACtB,IAAI;CAEJ,IAAI,CAAC,UACJ,cAAc,qBAAqB,SAAS,KAAK,IAAI,GAAG;MAExD,QAAQ,iBAAiB,UAAU,UAAU;EAC5C,IAAI,MAAM,WAAW,GACpB,IAAI,oBAAoB;GAAC,IAAI,KAAK;GAAI,MAAM,OAAO,IAAI;EAAC,CAAC;OAEzD,IAAI,cAAc,KAAK,EAAE;CAE3B,CAAC;CAIF,IAAI;CACJ,IAAI,MAAM,qBAAqB;EAC9B,MAAM,iBAAiB,OAAO,IAAI,OAAO,SAAS;EAClD,MAAM,aAAa,qBAAqB;EACxC,WAAW,MAAM,OAAO,GAAG,OAAO,EAAE;EACpC,WAAW,MAAM,MAAM,GAAG,eAAe;EACzC,WAAW,MAAM,aAAa;EAC9B,MAAM,aAAa,YAAY,QAAQ;EAEvC,MAAM,cAAc,yBAAyB,YAAY,KAAK,IAAI,OAAO,GAAG,gBAAgB,UAAU,OAAO,GAAG;EAEhH,MAAM,uBAA6B;GAClC,WAAW,MAAM,UAAU;GAC3B,WAAW,MAAM,YAAY;EAC9B;EACA,MAAM,uBAA6B;GAClC,WAAW,MAAM,UAAU;GAC3B,WAAW,MAAM,YAAY;EAC9B;EACA,QAAQ,iBAAiB,cAAc,cAAc;EACrD,QAAQ,iBAAiB,cAAc,cAAc;EAErD,2BAAiC;GAChC,YAAY;GACZ,QAAQ,oBAAoB,cAAc,cAAc;GACxD,QAAQ,oBAAoB,cAAc,cAAc;EACzD;CACD;CAGA,MAAM,uBAA6B;EAClC,MAAM,UAAU,IAAI,gBAAgB;GAAC,IAAI,KAAK;GAAI,MAAM,OAAO,IAAI;EAAC,CAAC;EACrE,IAAI,WAAW,QAAQ,SAAS,GAAG;GAClC,UAAU,YAAY;GACtB,UAAU,MAAM,UAAU;EAC3B,OACC,UAAU,MAAM,UAAU;CAE5B;CACA,MAAM,iBAAiB,MAAwB;EAC9C,MAAM,UAAU;EAChB,MAAM,UAAU;EAChB,IAAI,OAAO,EAAE,UAAU;EACvB,IAAI,MAAM,EAAE,UAAU;EACtB,MAAM,UAAU,OAAO,aAAa,UAAU,cAAc;EAC5D,MAAM,SAAS,OAAO,cAAc,UAAU,eAAe;EAC7D,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,OAAO,CAAC;EAC1C,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,MAAM,CAAC;EACvC,UAAU,MAAM,OAAO,GAAG,KAAK;EAC/B,UAAU,MAAM,MAAM,GAAG,IAAI;CAC9B;CACA,MAAM,uBAA6B;EAClC,UAAU,MAAM,UAAU;CAC3B;CACA,QAAQ,iBAAiB,cAAc,cAAc;CACrD,QAAQ,iBAAiB,aAAa,aAAa;CACnD,QAAQ,iBAAiB,cAAc,cAAc;CACrD,MAAM,uBAA6B;EAClC,QAAQ,oBAAoB,cAAc,cAAc;EACxD,QAAQ,oBAAoB,aAAa,aAAa;EACtD,QAAQ,oBAAoB,cAAc,cAAc;CACzD;CAEA,MAAM,QAOF;EAAC,KAAK;EAAS,cAAc;CAAK;CACtC,IAAI,gBAAgB,KAAA,GACnB,MAAM,cAAc;CAErB,IAAI,uBAAuB,KAAA,GAC1B,MAAM,qBAAqB;CAE5B,IAAI,mBAAmB,KAAA,GACtB,MAAM,iBAAiB;CAExB,SAAS,IAAI,KAAK,IAAI,KAAK;AAC5B;;;;;;;;;;AAWA,SAAgB,gBAAgB,MAAqB,OAAmB,KAA+B;CACtG,MAAM,EACL,SACA,SACA,OACA,QACA,OACA,eACA,aACA,YACA,YACA,qCACA,YACA,eACA,eACG;CAEJ,MAAM,EAAC,iBAAiB,eAAe,UAAU,gBAAe;CAChE,MAAM,WAAW,QAAQ;CACzB,MAAM,gBAAgB,mBAAmB,QAAQ;CAGjD,MAAM,cAAc,QAAQ,MAAM,MAAM,YAAY,MAAM,WAAW,CAAC;CACtE,cAAc,eAAe;CAC7B,IAAI,iBAAiB,EAAC,OAAO,GAAG,WAAW,IAAG,CAAC;CAG/C,IAAI,aAAa,GAAG;EACnB,MAAM,IAAI,GAAG,KAAK;EAClB,EAAE,MAAM,SAAS,GAAG,WAAW;EAC/B,gBAAgB,OAAO,CAAC;CACzB;CAEA,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;EAC5C,MAAM,SAAS,aAAa;EAC5B,MAAM,SAAS,GAAG,KAAK;EACvB,IAAI,QAAQ;GACX,QAAQ,GAAG,WAAW;GACtB,YAAY,SAAS,MAAM,IAAI,oBAAoB;GACnD,cAAc;EACf,CAAC;EACD,gBAAgB,OAAO,MAAM;CAC9B;CAGA,IAAI,gBAAgB,GAAG;EACtB,MAAM,IAAI,GAAG,KAAK;EAClB,EAAE,MAAM,SAAS,GAAG,cAAc;EAClC,gBAAgB,OAAO,CAAC;CACzB;CAGA,IAAI,eAAe;EAAC,OAAO,GAAG,WAAW;EAAK,QAAQ,GAAG,cAAc;CAAG,CAAC;CAG3E,MAAM,WAAsB,CAAC;CAC7B,KAAK,MAAM,SAAS,CAAC,GAAG,cAAc,QAAQ,GAC7C,IAAI,UAAU,UACb,SAAS,KAAK,KAAK;CAGrB,KAAK,MAAM,QAAQ,UAClB,cAAc,YAAY,IAAI;CAI/B,cAAc,QAAQ;CAGtB,KAAK,MAAM,EAAC,aAAa,oBAAoB,yBAAwB,YAAY,OAAO,GAAG;EAC1F,cAAc;EACd,qBAAqB;EACrB,sBAAsB;CACvB;CACA,YAAY,MAAM;CAGlB,IAAI,UAAU,OACb,4BAA4B,eAAe,UAAU,OAAO,aAAa;CAI1E,IAAI,UAAU,oBAAoB,eAAe,KAAK;CACtD,OAAO,WAAW,aAAa;EAC9B,MAAM,IAAI,OAAO,IAAI,OAAO;EAC5B,MAAM,OAAO,GAAG,KAAK;EACrB,IAAI,MAAM;GACT,UAAU;GACV,MAAM,GAAG,EAAE;GACX,KAAK;GACL,OAAO;GACP,QAAQ,GAAG,cAAc;GACzB,YAAY;GACZ,eAAe;EAChB,CAAC;EACD,cAAc,aAAa,MAAM,QAAQ;EACzC,UAAU,kBAAkB,SAAS,KAAK;CAC3C;CAGA,MAAM,SAAS,OAAO,oBAAI,IAAI,KAAK,CAAC;CACpC,MAAM,iBAAiB;CACvB,IAAI,MAAM,mBAAmB,UAAU,KAAK,UAAU,aAAa,gBAAgB;EAClF,MAAM,YAAY,GAAG,KAAK;EAC1B,UAAU,YAAY;EACtB,IAAI,WAAW;GACd,UAAU;GACV,MAAM,GAAG,OAAO;GAChB,KAAK;GACL,OAAO,GAAG,eAAe;GACzB,QAAQ,GAAG,cAAc;GACzB,YAAY;GACZ,eAAe;GACf,QAAQ;EACT,CAAC;EACD,cAAc,aAAa,WAAW,QAAQ;CAC/C;CAEA,MAAM,iBAAiB,IAAI,IAAI,YAAY,KAAK,SAAS,KAAK,EAAE,CAAC;CAGjE,KAAK,MAAM,QAAQ,aAAa;EAC/B,MAAM,SAAS,QAAQ,IAAI,KAAK,EAAE;EAClC,IAAI,WAAW,KAAA,GACd;EAGD,IAAI,OAAO,SAAS,aACnB,gBAAgB,eAAe,UAAU,MAAM,QAAQ,YAAY,aAAa,KAAK,OAAO,KAAK,SAAS;OAE1G,UAAU,eAAe,UAAU,MAAM,QAAQ,YAAY,aAAa,OAAO,KAAK,KAAK,SAAS;CAEtG;CAIA,sBAAsB,UADD,MAAM,QAAQ,SAAS,eAAe,IAAI,KAAK,YAAY,KAAK,eAAe,IAAI,KAAK,YAAY,CAC9E,GAAG,YAAY,eAAe,YAAY,qCAAqC,GAAG;AAC9H;;;ACppBA,SAAgB,eAAe,OAAiD;CAC/E,MAAM,wBAAQ,IAAI,IAAoB;CACtC,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACtC,MAAM,OAAO,MAAM;EACnB,IAAI,SAAS,KAAA,GACZ,MAAM,IAAI,KAAK,IAAI,CAAC;CAEtB;CACA,OAAO;AACR;AAEA,SAAgB,UAAU,MAAoB;CAC7C,OAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE;AACtC;AAEA,SAAgB,qBAAqB,aAA4D;CAChG,MAAM,sBAAM,IAAI,IAAgC;CAChD,KAAK,MAAM,cAAc,aAAa;EACrC,MAAM,SAAS,iBAAiB,MAAM,UAAU;EAChD,MAAM,UAAU,UAAU,UAAU,OAAO,IAAI,CAAC;EAChD,IAAI,IAAI,SAAS;GAChB,MAAM,OAAO;GACb,GAAI,OAAO,UAAU,KAAA,IAAY,CAAC,IAAI,EAAC,OAAO,OAAO,MAAK;GAC1D,GAAI,OAAO,cAAc,KAAA,IAAY,CAAC,IAAI,EAAC,WAAW,OAAO,UAAS;EACvE,CAAC;CACF;CACA,OAAO;AACR;AAEA,SAAgB,qBAAqB,MAAyC;CAC7E,IAAI,SAAS,KAAA,GACZ,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;CAGtB,MAAM,6BAAa,IAAI,IAAY;CACnC,KAAK,MAAM,OAAO,MAAM;EACvB,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,KAAK,MAAM,GAC9C,MAAM,IAAI,MAAM,iDAAiD;EAElE,WAAW,IAAI,GAAG;CACnB;CACA,OAAO;AACR;AAEA,SAAgB,qBAAqB,OAAyC;CAC7E,MAAM,QAAQ,cAAc,KAAK;CACjC,MAAM,gCAAgB,IAAI,IAAY;CACtC,MAAM,QAAQ,CAAC,GAAG,KAAK;CACvB,OAAO,MAAM,SAAS,GAAG;EACxB,MAAM,OAAO,MAAM,IAAI;EACvB,IAAI,SAAS,KAAA,GACZ;EAED,IAAI,KAAK,SAAS,SAAS,GAC1B,cAAc,IAAI,KAAK,EAAE;EAE1B,KAAK,MAAM,SAAS,KAAK,UACxB,MAAM,KAAK,KAAK;CAElB;CACA,OAAO;AACR;AAEA,SAAgB,sBAAsB,OAAyC;CAC9E,MAAM,gBAAgB,qBAAqB,KAAK;CAChD,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,QAAQ,OAClB,IAAI,KAAK,SAAS,aAAa,KAAK,QAAQ,cAAc,IAAI,KAAK,EAAE,GACpE,YAAY,IAAI,KAAK,EAAE;CAGzB,OAAO;AACR;;;AC7EA,MAAMC,mBAAiB;AAEvB,SAAgB,eACf,gBACA,UACA,WACA,kBACA,WACO;CACP,eAAe,iBAAiB,gBAAgB,MAAoB;EACnE,IAAI,EAAE,WAAW,GAChB;EAED,EAAE,eAAe;EACjB,EAAE,gBAAgB;EAElB,MAAM,SAAS,EAAE;EACjB,MAAM,aAAa,OAAO,WAAW,SAAS,MAAM,KAAK,KAAK;EAE9D,SAAS,OAAO,IAAwB;GAEvC,IAAI,WAAW,cADJ,GAAG,UAAU;GAExB,MAAM,YAAY,UAAU;GAC5B,IAAI,YAAY,GACf,WAAW,KAAK,IAAIA,kBAAgB,KAAK,IAAI,UAAU,YAAY,gBAAgB,CAAC;GAErF,WAAW,KAAK,IAAIA,kBAAgB,QAAQ;GAC5C,SAAS,MAAM,QAAQ,GAAG,SAAS;GACnC,SAAS,MAAM,WAAW,GAAG,SAAS;GACtC,SAAS,MAAM,WAAW,GAAG,SAAS;EACvC;EAEA,SAAS,OAAa;GACrB,OAAO,oBAAoB,eAAe,MAAM;GAChD,OAAO,oBAAoB,aAAa,IAAI;GAE5C,UADmB,OAAO,WAAW,SAAS,MAAM,KACjC,CAAC;EACrB;EAEA,OAAO,iBAAiB,eAAe,MAAM;EAC7C,OAAO,iBAAiB,aAAa,IAAI;CAC1C,CAAC;AACF;ACtCA,MAAa,oBAAoB;AACjC,MAAa,oBAAoB;AACjC,MAAM,iBAAiB;AAcvB,SAAgB,qBAAqB,SAA8C;CAClF,MAAM,EACL,WACA,cACA,gBACA,kBACA,qBACA,kBACA,wBACA,wBACA,qBACG;CAEJ,IAAI,QAAQ;CAEZ,IAAI,aAAa,GAChB,OAAO;CAGR,IAAI,mBAAmB,MACtB,QAAQ;MACF,IAAI,qBAAqB,KAAA,GAC/B,QAAQ;MACF,IAAI,uBAAuB,aAAa,kBAAkB;EAChE,MAAM,aAAa,KAAK,MAAM,YAAY,sBAAsB;EAChE,QAAQ,KAAK,IAAI,cAAc,KAAK,IAAI,wBAAwB,UAAU,CAAC;CAC5E,OAAO;EACN,MAAM,kBAAkB,KAAK,MAAM,YAAY,iBAAiB;EAChE,MAAM,kBAAkB,KAAK,MAAM,YAAY,iBAAiB;EAChE,QAAQ,KAAK,IAAI,iBAAiB,KAAK,IAAI,cAAc,eAAe,CAAC;CAC1E;CAEA,MAAM,aAAa,KAAK,IAAI,gBAAgB,YAAY,gBAAgB;CACxE,QAAQ,KAAK,IAAI,OAAO,UAAU;CAElC,OAAO,KAAK,IAAI,gBAAgB,KAAK,MAAM,KAAK,CAAC;AAClD;;;AC2GA,MAAM,WAAW;AACjB,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,aAAb,MAA6G;CAC5G;CACA;CACA;CACA,SAA4B;CAC5B;CACA,cAA6B;CAC7B,aAAa;CACb,cAAc;CACd,SAAwB;CACxB,aAAa;CACb,iCAA0B,IAAI,IAAkB;CAChD;CACA,iBAAoD;CACpD,kBAAiC;CAEjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,kBAAyC;CACzC;;;;;;;;;CAUA,YAAmB,WAAwB,OAAqB,CAAC,GAAG;EACnE,KAAKC,aAAa;EAElB,KAAKG,SAAS,KAAK,SAAS;EAC5B,KAAKF,QAAQ;EACb,KAAKG,aAAa,CAAC;EACnB,KAAKC,6BAAa,IAAI,IAAI;EAC1B,KAAKC,UAAU,mBAAmB,KAAK,MAAM;EAC7C,KAAKC,WAAW,KAAK,eAAe,mBAAmB,KAAKD,OAAO;EACnE,KAAKE,qBAAqB,KAAK,qBAAqB;EACpD,KAAKC,6BAA6B;EAClC,KAAKC,wBAAwB,KAAK,iBAAiB,iBAAiB,KAAKH,QAAQ;EACjF,KAAKI,UAAU,KAAK,UAAU;EAC9B,KAAKC,oBAAoB,KAAK,oBAAA;EAC9B,KAAKC,eAAe,qBAAqB,KAAK,eAAe,KAAKP,QAAQ,WAAW;EACrF,KAAKQ,qBAAqB,qBAAqB,KAAK,eAAe,CAAC,CAAC;EACrE,KAAKC,+BAAe,IAAI,IAAI;EAE5B,KAAKC,OAAO,KAAKC,sBAAsB;EAEvC,KAAKC,UAAU;EACf,KAAKC,YAAY;EAEjB,UAAU,OAAO,KAAKC,KAAK;EAE3B,KAAKC,YAAY;EAEjB,KAAKC,2BAA2B;EAChC,KAAKC,qBAAqB;CAC3B;CAEA,wBAAiF;EAChF,OAAO;GACN,cAAc,OAAa;IAC1B,IAAI,KAAKC,gBAAgB,IACxB;IAED,KAAKA,cAAc;IACnB,IAAI,KAAKA,gBAAgB,MAAM;KAC9B,MAAM,OAAO,KAAKC,UAAU,KAAKD,WAAW;KAC5C,IAAI,SAAS,KAAA,GACZ,KAAUpB,WAAW,cAAc;MAAO;MAAuC,UAAU;KAAI,CAAC;IAElG;IACA,KAAKsB,gBAAgB;GACtB;GACA,oBAAoB,YAAkB;IACrC,KAAUtB,WAAW,oBAAoB;KAAC,MAAM,QAAQ;KAAuC,UAAU;IAAI,CAAC;GAC/G;GACA,mBAAmB,YAAkB;IACpC,KAAUA,WAAW,oBAAoB;KAAC,MAAM,QAAQ;KAAuC,UAAU;IAAI,CAAC;GAC/G;GACA,aAAa,YAAkB;IAC9B,IAAI,CAAC,KAAKF,eAAe,IAAI,QAAQ,EAAE,GAAG;KACzC,MAAM,OAAO,KAAKyB,QAAQ,MAAM,MAAM,MAAM,EAAE,OAAO,QAAQ,EAAE;KAC/D,IAAI,SAAS,KAAA,GACZ,KAAKzB,eAAe,IAAI,QAAQ,IAAI,IAAI;IAE1C;IACA,MAAM,MAAM,QAAQ,UAAU,YAAY,EAAE,MAAM,GAAG,EAAE;IACvD,KAAK0B,WAAW,QAAQ,IAAI,EAAC,WAAW,IAAG,CAAC;IAC5C,KAAKF,gBAAgB;GACtB;GACA,kBAAkB,OAAO,YAA8B;IACtD,MAAM,OAAO,KAAKD,UAAU,QAAQ,EAAE;IACtC,IAAI,SAAS,KAAA,GAAW;KACvB,MAAM,aAAa,KAAK,SAAS,cAAc,UAAU,KAAK,OAAO,IAAI,QAAQ;KACjF,MAAM,SAAS,KAAKrB,WAAW,aAAa;MACrC;MACN,cAAc,QAAQ;MACtB;MACA,UAAU;KACX,CAAC;KACD,IAAI,kBAAkB;UACjB,CAAE,MAAM,QAAS;OACpB,MAAM,WAAW,KAAKF,eAAe,IAAI,QAAQ,EAAE;OACnD,IAAI,aAAa,KAAA,GAChB,KAAK0B,WAAW,QAAQ,IAAI,EAAC,WAAW,SAAS,UAAS,CAAC;MAE7D;YACM,IAAI,CAAC,QAAQ;MACnB,MAAM,WAAW,KAAK1B,eAAe,IAAI,QAAQ,EAAE;MACnD,IAAI,aAAa,KAAA,GAChB,KAAK0B,WAAW,QAAQ,IAAI,EAAC,WAAW,SAAS,UAAS,CAAC;KAE7D;IACD;IACA,KAAK1B,eAAe,MAAM;IAC1B,KAAKwB,gBAAgB;IACrB,OAAO;GACR;GACA,eAAe,YAAkB;IAChC,IAAI,CAAC,KAAKxB,eAAe,IAAI,QAAQ,EAAE,GAAG;KACzC,MAAM,OAAO,KAAKyB,QAAQ,MAAM,MAAM,MAAM,EAAE,OAAO,QAAQ,EAAE;KAC/D,IAAI,SAAS,KAAA,GACZ,KAAKzB,eAAe,IAAI,QAAQ,IAAI,IAAI;IAE1C;IACA,KAAK0B,WAAW,QAAQ,IAAI,EAAC,SAAS,QAAQ,QAAO,CAAC;IACtD,KAAKF,gBAAgB;GACtB;GACA,oBAAoB,OAAO,YAA8B;IACxD,MAAM,OAAO,KAAKD,UAAU,QAAQ,EAAE;IACtC,IAAI,SAAS,KAAA,KAAa,KAAK,SAAS,aAAa;KACpD,MAAM,eAAe,UAAU,KAAK,SAAS;KAC7C,MAAM,aAAa,UAAU,KAAK,OAAO;KACzC,MAAM,mBAAmB,UAAU,YAAY,YAAY;KAC3D,MAAM,SAAS,KAAKrB,WAAW,eAAe;MACvC;MACN;MACA;MACA;MACA,UAAU;KACX,CAAC;KACD,IAAI,kBAAkB;UACjB,CAAE,MAAM,QAAS;OACpB,MAAM,WAAW,KAAKF,eAAe,IAAI,QAAQ,EAAE;OACnD,IAAI,aAAa,KAAA,KAAa,SAAS,SAAS,aAC/C,KAAK0B,WAAW,QAAQ,IAAI,EAAC,SAAS,SAAS,QAAO,CAAC;MAEzD;YACM,IAAI,CAAC,QAAQ;MACnB,MAAM,WAAW,KAAK1B,eAAe,IAAI,QAAQ,EAAE;MACnD,IAAI,aAAa,KAAA,KAAa,SAAS,SAAS,aAC/C,KAAK0B,WAAW,QAAQ,IAAI,EAAC,SAAS,SAAS,QAAO,CAAC;KAEzD;IACD;IACA,KAAK1B,eAAe,MAAM;IAC1B,KAAKwB,gBAAgB;IACrB,OAAO;GACR;GACA,qBAAqB,YAAkB;IACtC,IAAI,CAAC,KAAKxB,eAAe,IAAI,QAAQ,EAAE,GAAG;KACzC,MAAM,OAAO,KAAKyB,QAAQ,MAAM,MAAM,MAAM,EAAE,OAAO,QAAQ,EAAE;KAC/D,IAAI,SAAS,KAAA,GACZ,KAAKzB,eAAe,IAAI,QAAQ,IAAI,IAAI;IAE1C;IACA,KAAK0B,WAAW,QAAQ,IAAI,EAAC,iBAAiB,QAAQ,gBAAe,CAAC;IACtE,KAAKF,gBAAgB;GACtB;GACA,0BAA0B,OAAO,YAA8B;IAC9D,MAAM,OAAO,KAAKD,UAAU,QAAQ,EAAE;IACtC,IAAI,SAAS,KAAA,GAAW;KACvB,MAAM,SAAS,KAAKrB,WAAW,mBAAmB;MAC3C;MACN,oBAAoB,QAAQ;MAC5B,UAAU;KACX,CAAC;KACD,IAAI,kBAAkB;UACjB,CAAE,MAAM,QAAS;OACpB,MAAM,WAAW,KAAKF,eAAe,IAAI,QAAQ,EAAE;OACnD,IAAI,aAAa,KAAA,KAAa,SAAS,SAAS,aAC/C,KAAK0B,WAAW,QAAQ,IAAI,EAAC,iBAAiB,SAAS,gBAAe,CAAC;MAEzE;YACM,IAAI,CAAC,QAAQ;MACnB,MAAM,WAAW,KAAK1B,eAAe,IAAI,QAAQ,EAAE;MACnD,IAAI,aAAa,KAAA,KAAa,SAAS,SAAS,aAC/C,KAAK0B,WAAW,QAAQ,IAAI,EAAC,iBAAiB,SAAS,gBAAe,CAAC;KAEzE;IACD;IACA,KAAK1B,eAAe,MAAM;IAC1B,KAAKwB,gBAAgB;IACrB,OAAO;GACR;GACA,YAAY,aAAmB;IAC9B,MAAM,aAAa,KAAKD,UAAU,QAAQ;IAC1C,IAAI,eAAe,KAAA,GAClB,KAAUrB,WAAW,YAAY;KAAa;KAA6C,UAAU;IAAI,CAAC;GAE5G;GACA,wBAAwB,UAAgB;IACvC,KAAUA,WAAW,wBAAwB;KAAC;KAAO,UAAU;IAAI,CAAC;GACrE;GACA,sBAAsB,mBAAyB;IAC9C,KAAUA,WAAW,sBAAsB;KAAC,SAAS;KAAgB,UAAU;IAAI,CAAC;GACrF;GACA,eAAe,YAAkB;IAChC,MAAM,aAAa,KAAKqB,UAAU,QAAQ,YAAY;IACtD,MAAM,aAAa,KAAKA,UAAU,QAAQ,YAAY;IACtD,IAAI,eAAe,KAAA,KAAa,eAAe,KAAA,GAC9C,KAAUrB,WAAW,eAAe;KACnC,MAAM;KACM;KACA;KACZ,UAAU;IACX,CAAC;GAEH;GACA,cAAc,YAAkB;IAC/B,KAAUA,WAAW,cAAc;KAAC,MAAM;KAA0C,UAAU;IAAI,CAAC;GACpG;GACA,iBAAiB,YAAkB;IAClC,KAAUA,WAAW,iBAAiB;KAAC,MAAM;KAA0C,UAAU;IAAI,CAAC;GACvG;GACA,gBAAgB,YAA2B,KAAKA,WAAW,gBAAgB;IAAC,MAAM,QAAQ;IAAuC,UAAU;GAAI,CAAC,KAAK;EACtJ;CACD;;;;;;;;CASA,aAAoB,KAAiD;EACpE,KAAKyB,aAAa;EAClB,KAAKzB,aAAa;EAClB,KAAKY,OAAO,KAAKC,sBAAsB;CACxC;;;;;;;CAQA,OAAc,UAAqD;EAClE,KAAKY,aAAa;EAClB,MAAM,QAAQ,iBAAiB,MAAM,QAAQ;EAC7C,iBAAiB,MAAM,OAAO,MAAM,KAAK;EACzC,aAAa,MAAM,OAAO,MAAM,KAAK;EACrC,KAAKF,SAAS,gBAAgB,KAAK;EACnC,KAAKtB,aAAa,eAAe,KAAKsB,OAAO,KAAK;EAClD,KAAKZ,eAAe,sBAAsB,KAAKY,OAAO,KAAK;EAC3D,IAAI,KAAKG,eAAe,KAAKC,WAAW,MAAM;GAC7C,qBAAqB,KAAKA,MAAM;GAChC,KAAKA,SAAS;GACd,KAAKD,cAAc;EACpB;EACA,KAAKE,QAAQ;CACd;;;;;;;;;;CAWA,WAAkB,MAAmC;EACpD,KAAKH,aAAa;EAElB,OAAO,OAAO,KAAK5B,OAAO,IAAI;EAE9B,KAAKE,SAAS,KAAKF,MAAM,SAAS;EAElC,IAAI,iBAAiB;EAErB,IAAI,KAAK,WAAW,KAAA,GAAW;GAC9B,KAAKK,UAAU,mBAAmB,KAAK,MAAM;GAC7C,IAAI,KAAKL,MAAM,gBAAgB,KAAA,GAAW;IACzC,KAAKM,WAAW,mBAAmB,KAAKD,OAAO;IAC/C,KAAKI,wBAAwB,iBAAiB,KAAKH,QAAQ;IAC3D,iBAAiB;GAClB;GACA,IAAI,KAAKN,MAAM,gBAAgB,KAAA,GAC9B,KAAKY,eAAe,qBAAqB,KAAKP,QAAQ,WAAW;EAEnE;EAEA,IAAI,KAAK,gBAAgB,KAAA,GAAW;GACnC,KAAKC,WAAW,KAAK;GACrB,KAAKG,wBAAwB,KAAKT,MAAM,iBAAiB,iBAAiB,KAAKM,QAAQ;GACvF,iBAAiB;EAClB;EAEA,IAAI,kBAAkB,KAAKoB,WAAW,MACrC,KAAKM,uBAAuB;EAG7B,IAAI,KAAK,kBAAkB,KAAA,GAC1B,KAAKvB,wBAAwB,KAAK;EAGnC,IAAI,KAAK,WAAW,KAAA,GAAW;GAC9B,KAAKC,UAAU,KAAK;GACpB,KAAKS,MAAM,MAAM,SAAS,GAAG,KAAKT,QAAQ;EAC3C;EAEA,IAAI,KAAK,qBAAqB,KAAA,GAAW;GACxC,KAAKC,oBAAoB,KAAK;GAC9B,KAAKsB,WAAW,MAAM,WAAW,GAAG,KAAKtB,kBAAkB;EAC5D;EAEA,IAAI,KAAK,gBAAgB,KAAA,GACxB,KAAKC,eAAe,qBAAqB,KAAK,WAAW;EAG1D,IAAI,KAAK,gBAAgB,KAAA,GACxB,KAAKC,qBAAqB,qBAAqB,KAAK,WAAW;EAGhE,IAAI,KAAK,UAAU,KAAA,GAClB,KAAKO,YAAY;EAGlB,IAAI,KAAK,sBAAsB,KAAA,GAAW;GACzC,KAAKb,qBAAqB,KAAK;GAC/B,KAAKC,6BAA6B;GAClC,MAAM,eAAe,iBAAiB,KAAKF,QAAQ;GACnD,IAAI,iBAAiB,KAAKG,uBAAuB;IAChD,KAAKA,wBAAwB;IAC7B,iBAAiB;IACjB,KAAKuB,uBAAuB;GAC7B;EACD;EAEA,MAAM,kBACL,KAAK,kBAAkB,KAAA,KACvB,KAAK,wBAAwB,KAAA,KAC7B,KAAK,qBAAqB,KAAA,KAC1B,KAAK,2BAA2B,KAAA,KAChC,KAAK,2BAA2B,KAAA,KAChC,KAAK,qBAAqB,KAAA;EAE3B,IAAI,iBACH,KAAKX,2BAA2B;EAGjC,MAAM,oBAAoB,kBAAkB,KAAK,WAAW,KAAA,KAAa,KAAK,sBAAsB,KAAA;EAEpG,MAAM,qBACL,KAAK,UAAU,KAAA,KACf,KAAK,oBAAoB,KAAA,KACzB,KAAK,iBAAiB,KAAA,KACtB,KAAK,gBAAgB,KAAA,KACrB,KAAK,gBAAgB,KAAA,KACrB,KAAK,wCAAwC,KAAA,KAC7C,KAAK,wBAAwB,KAAA,KAC7B,KAAK,wBAAwB,KAAA,KAC7B,KAAK,kBAAkB,KAAA,KACvB,KAAK,gBAAgB,KAAA,KACrB,KAAK,WAAW,KAAA,KAChB,KAAK,qBAAqB,KAAA;EAI3B,IAAI,EAFoB,qBAAqB,sBAAsB,kBAGlE;EAGD,IAAI,KAAKQ,eAAe,KAAKC,WAAW,MAAM;GAC7C,qBAAqB,KAAKA,MAAM;GAChC,KAAKA,SAAS;GACd,KAAKD,cAAc;EACpB;EAEA,IAAI,qBAAqB,CAAC,oBACzB,KAAKK,YAAY;OACX,IAAI,CAAC,qBAAqB,oBAChC,KAAKC,gBAAgB;OAErB,KAAKJ,QAAQ;CAEf;;;;;;;;CASA,OAAc,IAAmB,eAAe,OAAa;EAC5D,KAAKH,aAAa;EAClB,IAAI,OAAO,MACV,KAAKL,cAAc;OACb;GACN,MAAM,OAAO,KAAKG,QAAQ,MAAM,MAAM,MAAM,EAAE,OAAO,EAAE;GACvD,IAAI,SAAS,KAAA,KAAa,cACzB,KAAUvB,WAAW,cAAc;IAAC;IAAM,UAAU;GAAI,CAAC;GAE1D,KAAKoB,cAAc;EACpB;EACA,IAAI,KAAKM,eAAe,KAAKC,WAAW,MAAM;GAC7C,qBAAqB,KAAKA,MAAM;GAChC,KAAKA,SAAS;GACd,KAAKD,cAAc;EACpB;EACA,KAAKE,QAAQ;CACd;;;;;;;CAQA,YAAmB,eAAe,OAAa;EAC9C,KAAKH,aAAa;EAClB,MAAM,UAAU,eAAe,KAAKQ,+BAA+B,KAAK,IAAI,CAAC;EAC7E,KAAKtB,aAAa,MAAM;EACxB,IAAI,KAAKe,eAAe,KAAKC,WAAW,MAAM;GAC7C,qBAAqB,KAAKA,MAAM;GAChC,KAAKA,SAAS;GACd,KAAKD,cAAc;EACpB;EACA,KAAKE,QAAQ;EACb,IAAI,QAAQ,SAAS,GACpB,KAAU5B,WAAW,sBAAsB;GAAC,OAAO;GAA4C,UAAU;EAAI,CAAC;CAEhH;;;;;;;CAQA,UAAiB,eAAe,OAAa;EAC5C,KAAKyB,aAAa;EAClB,MAAM,UAAU,eAAe,KAAKQ,+BAA+B,IAAI,IAAI,CAAC;EAC5E,KAAKtB,aAAa,MAAM;EACxB,IAAI,KAAKY,WAAW,MACnB,KAAK,MAAM,MAAM,qBAAqB,KAAKA,OAAO,KAAK,GACtD,KAAKZ,aAAa,IAAI,EAAE;EAG1B,IAAI,KAAKe,eAAe,KAAKC,WAAW,MAAM;GAC7C,qBAAqB,KAAKA,MAAM;GAChC,KAAKA,SAAS;GACd,KAAKD,cAAc;EACpB;EACA,KAAKE,QAAQ;EACb,IAAI,QAAQ,SAAS,GACpB,KAAU5B,WAAW,sBAAsB;GAAC,OAAO;GAA4C,UAAU;EAAI,CAAC;CAEhH;CAEA,+BAA+B,MAAuB;EACrD,IAAI,KAAKuB,WAAW,MACnB,OAAO,CAAC;EAET,MAAM,gBAAgB,qBAAqB,KAAKA,OAAO,KAAK;EAC5D,MAAM,UAAkB,CAAC;EACzB,KAAK,MAAM,MAAM,eAEhB,IAD0B,KAAKZ,aAAa,IAAI,EAC5B,MAAM,MAAM;GAC/B,MAAM,OAAO,KAAKU,UAAU,EAAE;GAC9B,IAAI,SAAS,KAAA,GACZ,QAAQ,KAAK,KAAK,SAAS,YAAY;IAAC,GAAG;IAAM;GAAI,IAAI,EAAC,GAAG,KAAI,CAAC;EAEpE;EAED,OAAO;CACR;;;;;;;;;CAUA,gBAAsD;EACrD,KAAKI,aAAa;EAClB,IAAI,KAAKF,WAAW,MACnB,OAAO,CAAC;EAET,MAAM,gBAAgB,qBAAqB,KAAKA,OAAO,KAAK;EAC5D,MAAM,SAAwC,CAAC;EAC/C,KAAK,MAAM,QAAQ,KAAKA,OAAO,OAC9B,IAAI,cAAc,IAAI,KAAK,EAAE,GAC5B,OAAO,KAAK;GAAC,IAAI,KAAK;GAAI,MAAM,KAAKZ,aAAa,IAAI,KAAK,EAAE;EAAC,CAAC;EAGjE,OAAO;CACR;;;;;CAMA,UAAuB;EACtB,IAAI,KAAKuB,YACR;EAED,KAAKA,aAAa;EAClB,KAAKC,UAAU,oBAAoB,UAAU,KAAKC,SAAS;EAC3D,IAAI,KAAKC,oBAAoB,MAC5B,KAAKA,gBAAgB,WAAW;OAEhC,OAAO,oBAAoB,UAAU,KAAKnB,0BAA0B;EAErE,IAAI,KAAKS,WAAW,MACnB,qBAAqB,KAAKA,MAAM;EAEjC,KAAKW,qBAAqB;EAC1B,KAAK,MAAM,EAAC,aAAa,oBAAoB,qBAAqB,oBAAmB,KAAKC,eAAe,YAAY,OAAO,GAAG;GAC9H,cAAc;GACd,qBAAqB;GACrB,sBAAsB;GACtB,iBAAiB;EAClB;EACA,cAAc,KAAK3C,UAAU;CAC9B;CAEA,WAAW,IAAY,OAAmD;EACzE,IAAI,KAAK2B,WAAW,MACnB;EAED,MAAM,QAAQ,KAAKtB,WAAW,IAAI,EAAE;EACpC,IAAI,UAAU,KAAA,GACb;EAED,MAAM,SAAS,KAAKsB,OAAO,MAAM;EACjC,IAAI,WAAW,KAAA,GACd;EAED,KAAKA,OAAO,MAAM,SAAS;GAAC,GAAG;GAAQ,GAAG;EAAK;CAChD;CAEA,UAAU,IAA8B;EACvC,OAAO,KAAKA,QAAQ,MAAM,MAAM,MAAM,EAAE,OAAO,EAAE;CAClD;CAEA,+BAAqC;EACpC,MAAM,aAAa,KAAKpB,SAAS,MAAM,MAAM,EAAE,OAAO,SAAS;EAC/D,IAAI,eAAe,KAAA,GAClB,IAAI,KAAKC,oBACR,OAAO,WAAW;OAElB,WAAW,UAAU;CAGxB;CAEA,oBAA6B,YAA4C;EACxE,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,OAAO,KAAKqC;EAClB,IAAI,SAAS,QAAQ,KAAK,OAAO,QAAQ,MAAM,MAAM,KAAK,QAAQ,KAAK;GACtE,KAAKA,iBAAiB;GACtB,KAAK7B,KAAK,oBAAoB;IAAC,IAAI,QAAQ;IAAI,MAAM,QAAQ;GAAI,CAAC;GAClE;EACD;EACA,KAAK6B,iBAAiB;GAAC,IAAI,QAAQ;GAAI,MAAM;EAAG;EAChD,KAAK7B,KAAK,cAAc,QAAQ,EAAE;CACnC;CAEA,kBAAiC;EAChC,CAAC,CAAC,WAAW,KAAK8B,cAAc,KAAKP;EACrC,KAAKb,gBAAgB;CACtB;CAEA,mCAAkD;EACjD,MAAM,gBAAgB,qBAAqB;GAC1C,WAAW,KAAK,IAAI,GAAG,KAAK1B,WAAW,WAAW;GAClD,cAAc,KAAKU;GACnB,gBAAgB,KAAKqC;GACrB,kBAAkB,KAAK9C,MAAM;GAC7B,qBAAqB,KAAKA,MAAM,uBAAuB;GACvD,kBAAkB,KAAKA,MAAM,oBAAA;GAC7B,wBAAwB,KAAKA,MAAM,0BAAA;GACnC,wBAAwB,KAAKA,MAAM,0BAAA;GACnC,kBAAkB,KAAKW;EACxB,CAAC;EACD,KAAKoC,UAAU,MAAM,QAAQ,GAAG,cAAc;EAC9C,KAAKA,UAAU,MAAM,WAAW,GAAG,cAAc;EACjD,KAAKA,UAAU,MAAM,WAAW,GAAG,cAAc;EACjD,KAAKd,WAAW,MAAM,WAAW,GAAG,KAAKtB,kBAAkB;CAC5D;CAEA,cAAc,OAA+B;EAE5C,MAAM,UAAU,YADF,cAAc,MAAM,KACF,GAAG,KAAKG,YAAY;EACpD,MAAM,CAAC,SAAS,SACf,KAAKd,MAAM,kBAAkB,KAAA,KAAa,KAAKA,MAAM,gBAAgB,KAAA,IAClE,CAAC,KAAKA,MAAM,eAAe,KAAKA,MAAM,WAAW,IACjD,eAAe,SAAS,EAAE;EAC9B,MAAM,eAAe,KAAKK,QAAQ,gBAAgB;EAClD,MAAM,oBAAoB,oBAAoB,OAAO,KAAKH,QAAQ,YAAY;EAE9E,MAAM,SAAS,kBAAkB,KAAKA,QAAQ,OAAO;EACrD,MAAM,aAAa,KAAK,KAAK,OAAO,IAAI,iBAAiB,CAAC,IAAI;EAC9D,MAAM,UAAU,cAAc,SAAS,MAAM;EAC7C,MAAM,QAAQ,WAAW,MAAM,OAAO,OAAO;EAE7C,MAAM,aAAa,KAAKQ,UAAU;EAClC,MAAM,WAAW,QAAQ;EACzB,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,MAAM,KAAKmC,aAAa,UAAU,IAAI,QAAQ;EAClF,MAAM,WAAW,KAAK,IAAI,WAAW,GAAG,KAAK,MAAM,KAAKA,aAAa,cAAc,UAAU,IAAI,WAAW,CAAC;EAC7G,MAAM,aAAa,aAAa;EAChC,MAAM,gBAAgB,KAAK,IAAI,IAAI,WAAW,IAAI,YAAY,UAAU;EAExE,OAAO;GACN;GACA,OAAO,KAAK3C;GACZ,qCAAqC,KAAKF,MAAM,uCAAuC;GACvF,qBAAqB,KAAKA,MAAM,uBAAuB;GACvD,qBAAqB,KAAKA,MAAM,uBAAuB;GACvD,aAAa,KAAKc;GAClB,YAAY,KAAKS;GACjB,WAAW,KAAKsB;GAChB;GACA;GACA,eAAe;GACf,aAAa;GACb;GACA;GACA;GACA;GACA;GACA;GACA;GACA,cAAc,KAAK7C,MAAM,gBAAgB;GACzC,iBAAiB,KAAKA,MAAM,mBAAmB;GAC/C,aAAa,KAAKY;GAClB,mBAAmB,KAAKC;GACxB,QAAQ,KAAKR;EACd;CACD;CAEA,gBAA+B;EAC9B,KAAKwB,cAAc;EACnB,MAAM,QAAQ,KAAKH;EACnB,IAAI,UAAU,MACb;EAED,MAAM,QAAQ,KAAKsB,cAAc,KAAK;EAEtC,iBAAiB,KAAKC,cAAc,KAAK;EACzC,KAAKC,oBAAoB,KAAK;EAC9B,gBAAgB,KAAKR,gBAAgB,OAAO,KAAK3B,IAAI;CACtD;CAEA,oBAAmC;EAClC,KAAKc,cAAc;EACnB,MAAM,QAAQ,KAAKH;EACnB,IAAI,UAAU,MACb;EAED,KAAKwB,oBAAoB,KAAKF,cAAc,KAAK,CAAC;CACnD;CAEA,oBAAoB,OAAyB;EAC5C,eACC,KAAKG,WACL,OACA;GACC,WAAW,OAAO;IACjB,MAAM,WAAW,CAAC,KAAKrC,aAAa,IAAI,EAAE;IAC1C,IAAI,UACH,KAAKA,aAAa,IAAI,EAAE;SAExB,KAAKA,aAAa,OAAO,EAAE;IAE5B,MAAM,OAAO,KAAKU,UAAU,EAAE;IAC9B,IAAI,SAAS,KAAA,GAAW;KACvB,MAAM,UAAU,KAAK,SAAS,YAAY;MAAC,GAAG;MAAM,MAAM;KAAQ,IAAI,EAAC,GAAG,KAAI;KAC9E,KAAUrB,WAAW,mBAAmB;MACvC,MAAM;MACN,UAAU;KACX,CAAC;IACF;IACA,KAAKsB,gBAAgB;GACtB;GACA,cAAc,OAAO,KAAKV,KAAK,cAAc,EAAE;GAC/C,aAAa,YAAY;IACxB,KAAK4B,iBAAiB,OAAO;GAC9B;GACA,oBAAoB,YAAY,KAAK5B,KAAK,oBAAoB,OAAO;GACrE,YAAY,OAAO,KAAKA,KAAK,YAAY,EAAE;EAC5C,GACA,KAAKT,UACL,KAAKC,kBACN;CACD;CAEA,wBAAuC;EACtC,KAAKsB,cAAc;EACnB,MAAM,QAAQ,KAAKH;EACnB,IAAI,UAAU,MACb;EAED,MAAM,QAAQ,KAAKsB,cAAc,KAAK;EAEtC,iBAAiB,KAAKC,cAAc,KAAK;EACzC,gBAAgB,KAAKP,gBAAgB,OAAO,KAAK3B,IAAI;CACtD;CAEA,yBAA+B;EAC9B,KAAK0B,qBAAqB;EAC1B,cAAc,KAAKW,WAAW;EAC9B,MAAM,WAAW,oBAAoB,KAAK9C,UAAU,KAAKD,OAAO;EAChE,KAAKgD,wBAAwB,QAAQ;EACrC,KAAKD,YAAY,OAAO,QAAQ;EAChC,KAAKX,uBAAuB,kBAAkB,UAAU,KAAKU,WAAW,KAAK7C,WAAW,YAAY;GACnG,KAAKS,KAAK,sBAAsB,OAAO;EACxC,CAAC;CACF;CAEA,wBAAwB,UAA6B;EACpD,MAAM,YAAY,SAAS,cAA2B,0BAA0B;EAChF,MAAM,cAAc,SAAS,cAA2B,4BAA4B;EACpF,IAAI,cAAc,MACjB,UAAU,iBAAiB,UAAU,MAAM;GAC1C,EAAE,gBAAgB;GAClB,KAAK,UAAU,IAAI;EACpB,CAAC;EAEF,IAAI,gBAAgB,MACnB,YAAY,iBAAiB,UAAU,MAAM;GAC5C,EAAE,gBAAgB;GAClB,KAAK,YAAY,IAAI;EACtB,CAAC;CAEH;CAEA,kBAAwB;EACvB,IAAI,KAAKc,eAAe,KAAKQ,YAC5B;EAED,KAAKR,cAAc;EACnB,KAAKC,SAAS,sBAAsB,KAAKC,OAAO;CACjD;CAEA,cAAoB;EACnB,MAAM,QAAQ,KAAK/B,MAAM,SAAS;EAClC,KAAKD,WAAW,QAAQ,WAAW;CACpC;CAEA,eAAqB;EACpB,IAAI,KAAKsC,YACR,MAAM,IAAI,WAAW,sBAAsB,8BAA8B;CAE3E;CAEA,YAAkB;EACjB,MAAM,OAAO,GAAG,KAAK;EACrB,KAAK,YAAY;EACjB,IAAI,MAAM;GACT,QAAQ,GAAG,KAAK3B,QAAQ;GACxB,UAAU;GACV,SAAS;GACT,eAAe;GACf,YAAY;GACZ,YAAY;EACb,CAAC;EACD,KAAKS,QAAQ;EAEb,MAAM,WAAW,GAAG,KAAK;EACzB,IAAI,UAAU;GAAC,MAAM;GAAK,UAAU;GAAQ,UAAU;GAAY,SAAS;EAAM,CAAC;EAClF,KAAK,OAAO,QAAQ;EACpB,KAAKmB,YAAY;EAEjB,MAAM,WAAW,GAAG,KAAK;EACzB,SAAS,QAAQ,UAAU;EAC3B,IAAI,UAAU;GACb,OAAO,GAAG,KAAK7B,sBAAsB;GACrC,YAAY;GACZ,UAAU;GACV,MAAM;GACN,QAAQ;GACR,YAAY;GACZ,aAAa;EACd,CAAC;EACD,KAAKsC,YAAY;EAEjB,MAAM,aAAa,GAAG,KAAK;EAC3B,IAAI,YAAY;GAAC,UAAU;GAAU,KAAK;GAAK,QAAQ;GAAM,YAAY;EAAwB,CAAC;EAClG,MAAM,WAAW,oBAAoB,KAAKzC,UAAU,KAAKD,OAAO;EAChE,KAAKgD,wBAAwB,QAAQ;EACrC,WAAW,OAAO,QAAQ;EAC1B,SAAS,OAAO,UAAU;EAC1B,KAAKD,cAAc;EAEnB,MAAM,WAAW,GAAG,KAAK;EACzB,SAAS,OAAO,QAAQ;EACxB,KAAKD,YAAY;EAEjB,KAAKV,uBAAuB,kBAAkB,UAAU,UAAU,KAAKnC,WAAW,YAAY;GAC7F,KAAKS,KAAK,sBAAsB,OAAO;EACxC,CAAC;EAED,SAAS,OAAO,QAAQ;EAExB,MAAM,YAAY,GAAG,KAAK;EAC1B,UAAU,QAAQ,UAAU;EAC5B,IAAI,WAAW;GAAC,YAAY;GAAK,UAAU;GAAY,UAAU,GAAG,KAAKJ,kBAAkB;EAAG,CAAC;EAC/F,KAAKsB,aAAa;EAElB,MAAM,cAAc,GAAG,KAAK;EAC5B,IAAI,aAAa;GAAC,UAAU;GAAU,KAAK;GAAK,QAAQ;GAAK,YAAY;EAAwB,CAAC;EAClG,UAAU,OAAO,WAAW;EAC5B,KAAKgB,eAAe;EAEpB,KAAKP,iBAAiB,oBAAoB;EAC1C,UAAU,OAAO,KAAKA,eAAe,eAAe;EACpD,SAAS,OAAO,SAAS;EAEzB,MAAM,iBAAiB,GAAG,KAAK;EAC/B,eAAe,YAAY;EAC3B,IAAI,gBAAgB;GACnB,UAAU;GACV,OAAO;GACP,KAAK;GACL,QAAQ;GACR,OAAO;GACP,QAAQ;GACR,QAAQ;EACT,CAAC;EACD,SAAS,OAAO,cAAc;EAE9B,eAAe,gBAAgB,UAAU,KAAK3C,YAAY,KAAKY,oBAAoB,eAAe;GACjG,KAAKmC,kBAAkB;GACvB,KAAK/B,KAAK,wBAAwB,UAAU;EAC7C,CAAC;CACF;CAEA,cAAoB;EACnB,KAAK2B,eAAe,cAAc,iBAAiB,UAAU,UAAU;GAEtE,IADe,MAAM,OACV,QAAQ,oDAAoD,GACtE;GAED,KAAKnB,cAAc;GACnB,KAAKE,gBAAgB;EACtB,CAAC;EAED,KAAKN,MAAM,iBAAiB,YAAY,UAAU;GACjD,IAAI,MAAM,QAAQ,YAAY,KAAKI,gBAAgB,MAAM;IACxD,MAAM,eAAe;IACrB,KAAKA,cAAc;IACnB,KAAKE,gBAAgB;GACtB;EACD,CAAC;EAED,KAAKa,UAAU,iBAAiB,UAAU,KAAKC,SAAS;CACzD;CAEA,uBAA6B;EAC5B,IAAI,OAAO,mBAAmB,aAAa;GAC1C,KAAKC,kBAAkB,IAAI,qBAAqB;IAC/C,KAAKnB,2BAA2B;GACjC,CAAC;GACD,KAAKmB,gBAAgB,QAAQ,KAAKzC,UAAU;EAC7C,OACC,OAAO,iBAAiB,UAAU,KAAKsB,0BAA0B;CAEnE;AACD"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["_exhaustive","toTask","MIN_PANE_WIDTH","#container","#opts","#dragOriginals","#scale","#callbacks","#taskIndex","#locale","#columns","#showAddTaskButton","#syncActionsColumnVisibility","#leftPaneDefaultWidth","#height","#timelineMinWidth","#weekendDays","#specialDaysByDate","#expandedIds","#cbs","#buildCallbackAdapter","#buildDom","#wireEvents","#root","#applyTheme","#applyResponsivePaneStyles","#setupResizeObserver","#selectedId","#findTask","#scheduleRender","#input","#patchTask","#assertAlive","#rafPending","#rafId","#render","#rebuildLeftPaneHeader","#rightPane","#renderGrid","#renderTimeline","#buildExpandCollapseAllPayload","#destroyed","#scrollEl","#onScroll","#resizeObserver","#columnResizeCleanup","#rightPaneRefs","#handleGridClick","#lastGridClick","#scrollTop","#userSplitWidth","#leftPane","#computeState","#rightHeader","#renderGridInternal","#leftBody","#leftHeader","#wireHeaderTreeControls"],"sources":["../src/lib/errors.ts","../src/lib/domain/tree.ts","../src/lib/domain/dependencies.ts","../src/lib/locale.ts","../src/lib/domain/dateMath.ts","../src/lib/timeline/scale.ts","../src/lib/timeline/pixelMapper.ts","../src/lib/timeline/layoutEngine.ts","../src/lib/rendering/linkRouter.ts","../src/lib/validation/schemas.ts","../src/lib/vanilla/dom/helpers.ts","../src/lib/vanilla/dom/timeHeader.ts","../src/lib/vanilla/dom/gridColumns.ts","../src/lib/vanilla/dom/leftPane.ts","../src/lib/vanilla/dom/dependencyLayer.ts","../src/lib/vanilla/interaction/drag.ts","../src/lib/vanilla/interaction/linkCreation.ts","../src/lib/vanilla/dom/rightPane.ts","../src/lib/vanilla/utils.ts","../src/lib/vanilla/splitter.ts","../src/lib/vanilla/responsive.ts","../src/lib/vanilla/gantt-chart.ts"],"sourcesContent":["export type GanttErrorCode =\n\t| 'PARENT_REFERENCE'\n\t| 'PARENT_CYCLE'\n\t| 'LINK_REFERENCE'\n\t| 'DEPENDENCY_CYCLE'\n\t| 'MILESTONE_LINK_TYPE'\n\t| 'DUPLICATE_LINK_PAIR'\n\t| 'INSTANCE_DESTROYED';\n\n/**\n * Domain-specific error with a machine-readable {@link GanttErrorCode}.\n */\nexport class GanttError extends Error {\n\tpublic readonly code: GanttErrorCode;\n\n\t/**\n\t * @param code - A machine-readable {@link GanttErrorCode} categorising the error.\n\t * @param message - A human-readable description.\n\t */\n\tpublic constructor(code: GanttErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'GanttError';\n\t\tthis.code = code;\n\t}\n}\n","import {type Task as GenTask, type ZodTaskInferred as Task} from '../validation/schemas.ts';\nimport {GanttError} from '../errors.ts';\n\n/**\n * A task node in the render tree, combining the flat {@link Task} input data\n * with computed hierarchy structure.\n *\n * Produced by {@link buildTaskTree}; consumed by virtualized row rendering\n * and the timeline layout engine.\n */\nexport type TaskNode = GenTask<Record<string, unknown>> & {\n\t/** Array of child task nodes in the tree hierarchy. */\n\tchildren: TaskNode[];\n\t/** 0 = root */\n\tdepth: number;\n};\n\nfunction detectParentCycles(tasks: Task[]): void {\n\tconst adj = new Map<number, number[]>();\n\tfor (const task of tasks) {\n\t\tadj.set(task.id, []);\n\t}\n\tfor (const task of tasks) {\n\t\tif (task.parent !== undefined) {\n\t\t\tconst parents = adj.get(task.parent);\n\t\t\tif (parents !== undefined) {\n\t\t\t\tparents.push(task.id);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst WHITE = 0,\n\t\tGRAY = 1,\n\t\tBLACK = 2;\n\tconst color = new Map<number, 0 | 1 | 2>();\n\tconst parent = new Map<number, number>();\n\n\tfor (const id of adj.keys()) {\n\t\tcolor.set(id, WHITE);\n\t}\n\n\tconst dfs = (u: number): void => {\n\t\tcolor.set(u, GRAY);\n\t\tfor (const v of adj.get(u) ?? []) {\n\t\t\tconst vc = color.get(v) ?? WHITE;\n\t\t\tif (vc === GRAY) {\n\t\t\t\tconst path: number[] = [v, u];\n\t\t\t\tlet cur = u;\n\t\t\t\twhile (cur !== v) {\n\t\t\t\t\tconst p = parent.get(cur);\n\t\t\t\t\tif (p === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tpath.push(p);\n\t\t\t\t\tcur = p;\n\t\t\t\t}\n\t\t\t\tthrow new GanttError('PARENT_CYCLE', `Parent cycle detected: ${[...path].reverse().join(' -> ')}`);\n\t\t\t}\n\t\t\tif (vc === WHITE) {\n\t\t\t\tparent.set(v, u);\n\t\t\t\tdfs(v);\n\t\t\t}\n\t\t}\n\t\tcolor.set(u, BLACK);\n\t};\n\n\tfor (const id of adj.keys()) {\n\t\tif ((color.get(id) ?? WHITE) === WHITE) {\n\t\t\tdfs(id);\n\t\t}\n\t}\n}\n\n/**\n * Builds a typed tree from a flat task array.\n * Order of tasks[] is irrelevant — parents need not precede children.\n *\n * @param tasks - The flat array of tasks to convert into a tree.\n * @returns Root-level {@link TaskNode} instances with populated `children`.\n * @throws {GanttError} When a task references a `parent` id that does not exist,\n * when a parent cycle is detected, or when a `parent` points to a\n * milestone or leaf task.\n */\nexport function buildTaskTree(tasks: Task[]): TaskNode[] {\n\tconst map = new Map<number, TaskNode>();\n\tconst roots: TaskNode[] = [];\n\n\t// Pass 0: validate — no parent may point to a milestone or leaf\n\tfor (const task of tasks) {\n\t\tif (task.parent !== undefined) {\n\t\t\tconst parentTask = tasks.find((t) => t.id === task.parent);\n\t\t\tif (parentTask !== undefined && (parentTask.kind === 'milestone' || parentTask.kind === 'task')) {\n\t\t\t\tthrow new GanttError('PARENT_REFERENCE', `Task id=${task.id} cannot have parent id=${task.parent} of kind '${parentTask.kind}'`);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Pass 1: allocate nodes\n\tfor (const task of tasks) {\n\t\tmap.set(task.id, {...task, children: [], depth: 0});\n\t}\n\n\t// Pass 2: detect parent cycles via DFS before wiring edges\n\tdetectParentCycles(tasks);\n\n\t// Pass 3: wire parent→child edges\n\tfor (const task of tasks) {\n\t\tconst node = map.get(task.id);\n\t\tif (node === undefined) {\n\t\t\tcontinue;\n\t\t} // unreachable\n\t\tif (task.parent !== undefined) {\n\t\t\tconst parent = map.get(task.parent);\n\t\t\tif (parent === undefined) {\n\t\t\t\tthrow new GanttError('PARENT_REFERENCE', `Task id=${task.id} references non-existent parent id=${task.parent}`);\n\t\t\t}\n\t\t\tparent.children.push(node);\n\t\t} else {\n\t\t\troots.push(node);\n\t\t}\n\t}\n\n\t// Pass 4: compute depths via DFS from roots\n\t(function setDepths(nodes: TaskNode[], d: number): void {\n\t\tfor (const n of nodes) {\n\t\t\tn.depth = d;\n\t\t\tsetDepths(n.children, d + 1);\n\t\t}\n\t})(roots, 0);\n\n\treturn roots;\n}\n\n/**\n * Flattens a tree into a visible row list.\n * A node's children are included only when its id is in `expandedIds`.\n *\n * @param roots - The root-level {@link TaskNode} instances of the tree.\n * @param expandedIds - Set of task IDs whose children should be rendered.\n * @returns A depth-first flattened array of visible {@link TaskNode} items.\n */\nexport function flattenTree(roots: TaskNode[], expandedIds: ReadonlySet<number>): TaskNode[] {\n\tconst rows: TaskNode[] = [];\n\tfunction walk(node: TaskNode): void {\n\t\trows.push(node);\n\t\tif (node.children.length > 0 && expandedIds.has(node.id)) {\n\t\t\tfor (const child of node.children) {\n\t\t\t\twalk(child);\n\t\t\t}\n\t\t}\n\t}\n\tfor (const root of roots) {\n\t\twalk(root);\n\t}\n\treturn rows;\n}\n\n/**\n * Returns `true` when a node has children in the tree.\n *\n * @param node - The {@link TaskNode} to inspect.\n * @returns `true` if `node.children.length > 0`.\n */\nexport function isParent(node: TaskNode): boolean {\n\treturn node.children.length > 0;\n}\n","import {type ZodLinkInferred as Link, type ZodTaskInferred as Task} from '../validation/schemas.ts';\nimport {GanttError} from '../errors.ts';\n\n/**\n * Detects circular dependencies in the link graph using DFS tri-colour marking.\n *\n * @param tasks - The task list (used to build the vertex set).\n * @param links - The dependency links defining the directed edges.\n * @throws {GanttError} When a cycle is detected, with a human-readable cycle path.\n */\nexport function detectCycles(tasks: Task[], links: Link[]): void {\n\t// Build adjacency list (directed: source → target)\n\tconst adj = new Map<number, number[]>();\n\tfor (const task of tasks) {\n\t\tadj.set(task.id, []);\n\t}\n\tfor (const link of links) {\n\t\tconst neighbors = adj.get(link.source);\n\t\tif (neighbors !== undefined) {\n\t\t\tneighbors.push(link.target);\n\t\t}\n\t}\n\n\tconst WHITE = 0,\n\t\tGRAY = 1,\n\t\tBLACK = 2;\n\tconst color = new Map<number, 0 | 1 | 2>();\n\tconst parent = new Map<number, number>();\n\n\tfor (const id of adj.keys()) {\n\t\tcolor.set(id, WHITE);\n\t}\n\n\tconst dfs = (u: number): void => {\n\t\tcolor.set(u, GRAY);\n\t\tfor (const v of adj.get(u) ?? []) {\n\t\t\tconst vc = color.get(v) ?? WHITE;\n\t\t\tif (vc === GRAY) {\n\t\t\t\t// Back-edge found — reconstruct cycle\n\t\t\t\tconst path: number[] = [v, u];\n\t\t\t\tlet cur = u;\n\t\t\t\twhile (cur !== v) {\n\t\t\t\t\tconst p = parent.get(cur);\n\t\t\t\t\tif (p === undefined) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tpath.push(p);\n\t\t\t\t\tcur = p;\n\t\t\t\t}\n\t\t\t\tthrow new GanttError('DEPENDENCY_CYCLE', `Circular dependency detected: ${[...path].reverse().join(' -> ')}`);\n\t\t\t}\n\t\t\tif (vc === WHITE) {\n\t\t\t\tparent.set(v, u);\n\t\t\t\tdfs(v);\n\t\t\t}\n\t\t}\n\t\tcolor.set(u, BLACK);\n\t};\n\n\tfor (const id of adj.keys()) {\n\t\tif ((color.get(id) ?? WHITE) === WHITE) {\n\t\t\tdfs(id);\n\t\t}\n\t}\n}\n\n/**\n * Validates that every link references existing task IDs and that no\n * duplicate (source, target) pairs exist.\n *\n * @param tasks - The task list (used as the reference set of valid IDs).\n * @param links - The dependency links to validate.\n * @throws {GanttError} When any link references a non-existent source or target task,\n * when a non-FS link connects to/from a milestone, or when duplicate\n * (source, target) pairs exist.\n */\nexport function validateLinkRefs(tasks: Task[], links: Link[]): void {\n\tconst ids = new Set(tasks.map((t) => t.id));\n\tconst taskById = new Map(tasks.map((t) => [t.id, t]));\n\tconst pairKeys = new Set<string>();\n\n\tfor (const link of links) {\n\t\tif (!ids.has(link.source)) {\n\t\t\tthrow new GanttError('LINK_REFERENCE', `Link id=${link.id}: source=${link.source} not found`);\n\t\t}\n\t\tif (!ids.has(link.target)) {\n\t\t\tthrow new GanttError('LINK_REFERENCE', `Link id=${link.id}: target=${link.target} not found`);\n\t\t}\n\n\t\tconst pairKey = `${link.source}:${link.target}`;\n\t\tif (pairKeys.has(pairKey)) {\n\t\t\tthrow new GanttError('DUPLICATE_LINK_PAIR', `Link id=${link.id}: duplicate pair source=${link.source} target=${link.target}`);\n\t\t}\n\t\tpairKeys.add(pairKey);\n\n\t\tif (link.type !== 'FS') {\n\t\t\tconst sourceTask = taskById.get(link.source);\n\t\t\tconst targetTask = taskById.get(link.target);\n\t\t\tif (sourceTask?.kind === 'milestone' || targetTask?.kind === 'milestone') {\n\t\t\t\tthrow new GanttError('MILESTONE_LINK_TYPE', `Link id=${link.id}: non-FS type '${link.type}' not allowed when connected to a milestone`);\n\t\t\t}\n\t\t}\n\t}\n}\n","export type LocaleLabelKey =\n\t| 'ariaTask'\n\t| 'ariaMilestone'\n\t| 'addSubtaskTitle'\n\t| 'expandAllTitle'\n\t| 'collapseAllTitle'\n\t| 'columnTaskName'\n\t| 'columnStartDate'\n\t| 'columnEndDate'\n\t| 'columnDuration'\n\t| 'columnQuarter';\n\nexport type ChartLocale = {\n\tcode: string;\n\tlabels?: Partial<Record<LocaleLabelKey, string>>;\n\tweekStartsOn?: 0 | 1 | 6;\n\tweekNumbering?: 'iso' | 'us' | 'simple';\n\tweekendDays?: number[];\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype IntlLocaleWithWeekInfo = Intl.Locale & {getWeekInfo?: () => {firstDay: number; weekend: number[]; minimalDays: number}};\n\nconst WEEK_START_REGION: Record<string, 0 | 1 | 6> = {\n\tUS: 0,\n\tCA: 0,\n\tMX: 0,\n\tJP: 0,\n\tPH: 0,\n\tBR: 0,\n\tCO: 0,\n\tVE: 0,\n\tPE: 0,\n\tEC: 0,\n\tCL: 0,\n\tAR: 0,\n\tUY: 0,\n\tPY: 0,\n\tBO: 0,\n\tGT: 0,\n\tHN: 0,\n\tSV: 0,\n\tNI: 0,\n\tCR: 0,\n\tPA: 0,\n\tDO: 0,\n\tPR: 0,\n\tIL: 0,\n\tSA: 0,\n\tKW: 0,\n\tQA: 0,\n\tBH: 0,\n\tOM: 0,\n\tYE: 0,\n\tMA: 0,\n\tDZ: 0,\n\tTN: 0,\n\tLY: 0,\n\tEG: 0,\n\tIQ: 0,\n\tJO: 0,\n\tSD: 0,\n\tSY: 0,\n\tLB: 0,\n\tPS: 0,\n\tAE: 6,\n\tIR: 6,\n\tAF: 6,\n\tDJ: 6,\n\tSO: 6,\n};\n\nconst WEEK_START_LANG: Record<string, 0 | 1 | 6> = {\n\tar: 6,\n\tfa: 6,\n};\n\nconst WEEK_NUMBERING_REGION: Record<string, 'iso' | 'us'> = {\n\tUS: 'us',\n\tCA: 'us',\n\tMX: 'us',\n\tBR: 'us',\n\tAR: 'us',\n\tCL: 'us',\n\tCO: 'us',\n\tPE: 'us',\n\tJP: 'us',\n\tKR: 'us',\n\tCN: 'us',\n\tTW: 'us',\n\tIN: 'us',\n\tPH: 'us',\n\tIL: 'us',\n\tSA: 'us',\n\tAE: 'us',\n\tIR: 'us',\n\tZA: 'us',\n\tAU: 'us',\n\tNZ: 'us',\n};\n\nconst WEEKEND_REGION: Record<string, number[]> = {\n\tAE: [5, 6],\n\tAF: [4, 5],\n\tDZ: [5, 6],\n\tBH: [5, 6],\n\tBD: [5, 6],\n\tEG: [5, 6],\n\tIQ: [5, 6],\n\tIL: [5, 6],\n\tJO: [5, 6],\n\tKW: [5, 6],\n\tLY: [5, 6],\n\tMV: [5, 6],\n\tMR: [5, 6],\n\tMA: [5, 6],\n\tOM: [5, 6],\n\tPK: [5, 6],\n\tPS: [5, 6],\n\tQA: [5, 6],\n\tSA: [5, 6],\n\tSD: [5, 6],\n\tSY: [5, 6],\n\tTN: [5, 6],\n\tYE: [5, 6],\n\tBN: [5, 0],\n\tIN: [0],\n\tUG: [0],\n\tNP: [6],\n\tIR: [5],\n\tDJ: [4, 5],\n\tSO: [5],\n\tMY: [5, 0],\n};\n\nexport const EN_US_LABELS: Record<LocaleLabelKey, string> = {\n\tariaTask: 'Task {0}',\n\tariaMilestone: 'Milestone {0}',\n\taddSubtaskTitle: 'Add subtask',\n\texpandAllTitle: 'Expand all',\n\tcollapseAllTitle: 'Collapse all',\n\tcolumnTaskName: 'Task name',\n\tcolumnStartDate: 'Start',\n\tcolumnEndDate: 'End',\n\tcolumnDuration: 'Duration',\n\tcolumnQuarter: 'Q',\n};\n\nfunction tryGetWeekInfo(code: string): {firstDay: number; weekend: number[]; minimalDays: number} | undefined {\n\ttry {\n\t\tif (typeof Intl !== 'undefined' && typeof Intl.Locale === 'function') {\n\t\t\tconst locale = new Intl.Locale(code) as IntlLocaleWithWeekInfo;\n\t\t\tconst fn = locale.getWeekInfo;\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\treturn fn.call(locale);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Not available — use fallback mapping table\n\t}\n\treturn undefined;\n}\n\n/**\n * Derives the first day of week (0=Sun, 1=Mon, 6=Sat) from a BCP 47 code.\n * Uses `Intl.Locale.getWeekInfo()` where available (Chromium, Safari 15.4+),\n * with a CLDR-based fallback table for Firefox and older runtimes.\n *\n * @param code - A BCP 47 language tag (e.g. `'en-US'`, `'de-DE'`).\n * @returns The first day of the week: `0` (Sunday), `1` (Monday), or `6` (Saturday).\n */\nexport function deriveWeekStartsOn(code: string): 0 | 1 | 6 {\n\tconst primary = code.split('-')[0]?.toLowerCase() ?? 'en';\n\tconst region = code.split('-')[1]?.toUpperCase();\n\n\tif (region !== undefined) {\n\t\tconst fromRegion = WEEK_START_REGION[region];\n\t\tif (fromRegion !== undefined) {\n\t\t\treturn fromRegion;\n\t\t}\n\t}\n\tconst fromLang = WEEK_START_LANG[primary];\n\tif (fromLang !== undefined) {\n\t\treturn fromLang;\n\t}\n\n\tconst info = tryGetWeekInfo(code);\n\tif (info !== undefined) {\n\t\tconst day = info.firstDay;\n\t\treturn (day === 7 ? 0 : day) as 0 | 1 | 6;\n\t}\n\n\treturn 1;\n}\n\n/**\n * Derives the week numbering scheme from a BCP 47 code.\n * Europe and ISO-aligned regions default to `'iso'`; Americas and others to `'us'`.\n *\n * @param code - A BCP 47 language tag (e.g. `'en-US'`, `'de-DE'`).\n * @returns The week numbering scheme: `'iso'`, `'us'`, or `'simple'`.\n */\nexport function deriveWeekNumbering(code: string): 'iso' | 'us' | 'simple' {\n\tconst region = code.split('-')[1]?.toUpperCase();\n\tif (region !== undefined) {\n\t\tconst fromRegion = WEEK_NUMBERING_REGION[region];\n\t\tif (fromRegion !== undefined) {\n\t\t\treturn fromRegion;\n\t\t}\n\t\tif (region in WEEK_START_REGION) {\n\t\t\treturn 'us';\n\t\t}\n\t}\n\n\tconst info = tryGetWeekInfo(code);\n\tif (info !== undefined) {\n\t\tif (info.minimalDays >= 4 && info.firstDay === 1) {\n\t\t\treturn 'iso';\n\t\t}\n\t\treturn 'us';\n\t}\n\n\treturn 'iso';\n}\n\n/**\n * Derives weekend days (0=Sun … 6=Sat) from a BCP 47 code.\n * Uses `Intl.Locale.getWeekInfo()` where available, with a CLDR-based fallback table.\n *\n * @param code - A BCP 47 language tag (e.g. `'en-US'`, `'de-DE'`).\n * @returns An array of weekend day indices (sorted ascending).\n */\nexport function deriveWeekendDays(code: string): number[] {\n\tconst region = code.split('-')[1]?.toUpperCase();\n\tif (region !== undefined) {\n\t\tconst fromRegion = WEEKEND_REGION[region];\n\t\tif (fromRegion !== undefined) {\n\t\t\tconst days = [...fromRegion];\n\t\t\tdays.sort((a, b) => a - b);\n\t\t\treturn days;\n\t\t}\n\t}\n\n\tconst info = tryGetWeekInfo(code);\n\tif (info !== undefined) {\n\t\tconst days = info.weekend.map((d: number) => (d === 7 ? 0 : d));\n\t\tdays.sort((a, b) => a - b);\n\t\treturn days;\n\t}\n\n\treturn [0, 6];\n}\n\n/**\n * Resolves a {@link ChartLocale} from either a full `ChartLocale` object or a BCP 47 string.\n * When given a string, derives `weekStartsOn`, `weekNumbering`, and `weekendDays` from CLDR conventions.\n *\n * @param raw - A {@link ChartLocale} object, a BCP 47 language tag string, or `undefined`.\n * @returns A fully resolved {@link ChartLocale} with defaults applied.\n */\nexport function resolveChartLocale(raw: ChartLocale | string | undefined): ChartLocale {\n\tif (raw === undefined) {\n\t\treturn {\n\t\t\tcode: 'en',\n\t\t\tlabels: EN_US_LABELS,\n\t\t\tweekStartsOn: 0,\n\t\t\tweekNumbering: 'iso',\n\t\t\tweekendDays: [0, 6],\n\t\t};\n\t}\n\tif (typeof raw !== 'string') {\n\t\tconst locale: ChartLocale = {\n\t\t\tcode: raw.code,\n\t\t\tweekStartsOn: raw.weekStartsOn ?? deriveWeekStartsOn(raw.code),\n\t\t\tweekNumbering: raw.weekNumbering ?? deriveWeekNumbering(raw.code),\n\t\t\tweekendDays: raw.weekendDays ?? deriveWeekendDays(raw.code),\n\t\t};\n\t\tif (raw.labels !== undefined) {\n\t\t\tlocale.labels = raw.labels;\n\t\t}\n\t\treturn locale;\n\t}\n\tconst code = raw;\n\treturn {\n\t\tcode,\n\t\tweekStartsOn: deriveWeekStartsOn(code),\n\t\tweekNumbering: deriveWeekNumbering(code),\n\t\tweekendDays: deriveWeekendDays(code),\n\t};\n}\n\nfunction isoWeek(date: Date): number {\n\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\tconst dayNum = d.getUTCDay() || 7;\n\td.setUTCDate(d.getUTCDate() + 4 - dayNum);\n\tconst yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n\treturn Math.ceil(((d.getTime() - yearStart.getTime()) / 86_400_000 + 1) / 7);\n}\n\nfunction usWeek(date: Date): number {\n\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\tconst yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n\tconst dayOfYear = Math.floor((d.getTime() - yearStart.getTime()) / 86_400_000);\n\tconst jan1Dow = yearStart.getUTCDay();\n\tconst daysToFirstWeekStart = jan1Dow === 0 ? 0 : -jan1Dow;\n\tconst weekStartDayOfYear = daysToFirstWeekStart;\n\tif (dayOfYear < weekStartDayOfYear) {\n\t\treturn 0;\n\t}\n\treturn Math.floor((dayOfYear - weekStartDayOfYear) / 7) + 1;\n}\n\nfunction simpleWeek(date: Date): number {\n\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\tconst yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n\tconst dayOfYear = Math.floor((d.getTime() - yearStart.getTime()) / 86_400_000);\n\treturn Math.ceil((dayOfYear + 1) / 7);\n}\n\n/**\n * Formats a week number according to the specified scheme.\n *\n * - `'iso'`: ISO 8601 (week 1 contains the first Thursday; Monday start).\n * - `'us'`: Week 1 contains January 1; Sunday start.\n * - `'simple'`: `Math.ceil(dayOfYear / 7)`.\n *\n * @param date - The date to compute the week number for.\n * @param scheme - The week numbering scheme: `'iso'`, `'us'`, or `'simple'`.\n * @returns The week number as a positive integer.\n */\nexport function formatWeekNumber(date: Date, scheme: 'iso' | 'us' | 'simple'): number {\n\tswitch (scheme) {\n\t\tcase 'iso': {\n\t\t\treturn isoWeek(date);\n\t\t}\n\t\tcase 'us': {\n\t\t\treturn usWeek(date);\n\t\t}\n\t\tcase 'simple': {\n\t\t\treturn simpleWeek(date);\n\t\t}\n\t}\n}\n\n/**\n * Formats a label template by replacing `{0}` with the given argument.\n *\n * @param template - The template string containing `{0}` as placeholder.\n * @param arg - The value to substitute for `{0}`.\n * @returns The formatted string with the placeholder replaced.\n */\nexport function formatLabel(template: string, arg: string): string {\n\treturn template.replaceAll('{0}', arg);\n}\n","import {type TimeScale} from '../timeline/scale.ts';\nimport {type ChartLocale, EN_US_LABELS, formatWeekNumber} from '../locale.ts';\n\n/**\n * Parses `YYYY-MM-DD` → UTC midnight `Date`.\n *\n * @param dateStr - An ISO-8601 date string in `YYYY-MM-DD` format.\n * @returns A `Date` representing UTC midnight of the given date.\n * @throws {Error} When `dateStr` does not represent a valid date.\n */\nexport function parseDate(dateStr: string): Date {\n\tconst d = new Date(`${dateStr}T00:00:00.000Z`);\n\tif (isNaN(d.getTime())) {\n\t\tthrow new Error(`Invalid date: \"${dateStr}\"`);\n\t}\n\treturn d;\n}\n\n/**\n * Returns `date + n` days using exact millisecond arithmetic.\n *\n * @param date - The base date.\n * @param days - Number of days to add (may be negative).\n * @returns A new `Date` offset by the given number of days.\n */\nexport function addDays(date: Date, days: number): Date {\n\treturn new Date(date.getTime() + days * 86_400_000);\n}\n\n/**\n * Returns `date + n` hours using exact millisecond arithmetic.\n *\n * @param date - The base date.\n * @param hours - Number of hours to add (may be negative).\n * @returns A new `Date` offset by the given number of hours.\n */\nexport function addHours(date: Date, hours: number): Date {\n\treturn new Date(date.getTime() + hours * 3_600_000);\n}\n\n/**\n * Difference in days (float). Positive when `b > a`.\n *\n * @param a - The earlier date.\n * @param b - The later date.\n * @returns The fractional number of days between the two dates.\n */\nexport function diffDays(a: Date, b: Date): number {\n\treturn (b.getTime() - a.getTime()) / 86_400_000;\n}\n\n/**\n * Difference in hours (float). Positive when `b > a`.\n *\n * @param a - The earlier date.\n * @param b - The later date.\n * @returns The fractional number of hours between the two dates.\n */\nexport function diffHours(a: Date, b: Date): number {\n\treturn (b.getTime() - a.getTime()) / 3_600_000;\n}\n\n/**\n * Returns the UTC start-of-day for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of the same calendar date.\n */\nexport function startOfDay(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n}\n\n/**\n * UTC start-of-week. Respects locale's `weekStartsOn` (0=Sun, 1=Mon, 6=Sat).\n *\n * @param date - Any `Date`.\n * @param weekStartsOn - First day of the week (`0`-Sun, `1`-Mon, `6`-Sat). Defaults to `1` (Monday).\n * @returns A new `Date` set to UTC midnight of the first day of the containing week.\n */\nexport function startOfWeek(date: Date, weekStartsOn: 0 | 1 | 6 = 1): Date {\n\tconst d = startOfDay(date);\n\tconst dow = d.getUTCDay();\n\tconst offset = (((dow - weekStartsOn) % 7) + 7) % 7;\n\treturn addDays(d, -offset);\n}\n\n/**\n * Returns the UTC start-of-month for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of the first day of the containing month.\n */\nexport function startOfMonth(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n}\n\n/**\n * Returns the UTC start-of-quarter for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of the first day of the containing quarter.\n */\nexport function startOfQuarter(date: Date): Date {\n\tconst month = date.getUTCMonth();\n\tconst quarterStartMonth = Math.floor(month / 3) * 3;\n\treturn new Date(Date.UTC(date.getUTCFullYear(), quarterStartMonth, 1));\n}\n\n/**\n * Returns the UTC start-of-year for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to UTC midnight of January 1 of the containing year.\n */\nexport function startOfYear(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), 0, 1));\n}\n\n/**\n * Returns the UTC start-of-hour for the given date.\n *\n * @param date - Any `Date`.\n * @returns A new `Date` set to the start of the containing UTC hour.\n */\nexport function startOfHour(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()));\n}\n\nfunction resolveQuarterLabel(locale: ChartLocale): string {\n\tif (locale.labels?.columnQuarter !== undefined) {\n\t\treturn locale.labels.columnQuarter;\n\t}\n\treturn EN_US_LABELS.columnQuarter;\n}\n\n/**\n * Formats a `Date` for the time-header label given the active scale.\n *\n * @param date - The date to format.\n * @param scale - The active {@link TimeScale} determining the label granularity.\n * @param locale - The {@link ChartLocale} used for formatting.\n * @returns A human-readable header label string.\n */\nexport function formatHeaderLabel(date: Date, scale: TimeScale, locale: ChartLocale): string {\n\tconst {code, weekNumbering: weekNumScheme = 'iso'} = locale;\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn `${String(date.getUTCHours()).padStart(2, '0')}:00`;\n\t\t}\n\t\tcase 'day': {\n\t\t\tconst day = date.toLocaleDateString(code, {weekday: 'short', timeZone: 'UTC'});\n\t\t\treturn `${date.getUTCDate()} ${day}`;\n\t\t}\n\t\tcase 'week': {\n\t\t\tconst wn = formatWeekNumber(date, weekNumScheme);\n\t\t\treturn `W${wn}`;\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn date.toLocaleDateString(code, {month: 'short', year: 'numeric', timeZone: 'UTC'});\n\t\t}\n\t\tcase 'quarter': {\n\t\t\treturn `${resolveQuarterLabel(locale)}${Math.floor(date.getUTCMonth() / 3) + 1} ${date.getUTCFullYear()}`;\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t}\n}\n\n/**\n * Returns the upper-level (month/year) label for a given scale column.\n * Used in the top header row of the timeline.\n *\n * @param date - The date to format.\n * @param scale - The active {@link TimeScale}. Determines how the upper label is computed.\n * @param locale - The {@link ChartLocale} used for formatting.\n * @returns A human-readable upper-level header label string.\n */\nexport function formatUpperLabel(date: Date, scale: TimeScale, locale: ChartLocale): string {\n\tconst {code} = locale;\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn date.toLocaleDateString(code, {month: 'long', day: 'numeric', year: 'numeric', timeZone: 'UTC'});\n\t\t}\n\t\tcase 'day':\n\t\tcase 'week': {\n\t\t\treturn date.toLocaleDateString(code, {month: 'long', year: 'numeric', timeZone: 'UTC'});\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t\tcase 'quarter': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn `${date.getUTCFullYear()}`;\n\t\t}\n\t}\n}\n\n/**\n * Returns the number of days in an inclusive range from `start` to `end`.\n *\n * @param start - The start date.\n * @param end - The end date.\n * @returns The number of days, inclusive.\n */\nexport function getRangeDays(start: Date, end: Date): number {\n\treturn Math.round(diffDays(start, end)) + 1;\n}\n\n/**\n * Calculates the end date for an inclusive range starting at `start` with a given duration in days.\n *\n * @param start - The start date.\n * @param durationDays - The number of days in the range (must be >= 1).\n * @returns The end date.\n */\nexport function getEndDate(start: Date, durationDays: number): Date {\n\treturn addDays(start, Math.max(0, durationDays - 1));\n}\n\n/**\n * Formats a `YYYY-MM-DD` string for display in the grid.\n *\n * @param dateStr - An ISO-8601 date string in `YYYY-MM-DD` format.\n * @param locale - The {@link ChartLocale} used for locale-aware formatting.\n * @returns A locale-formatted date string.\n */\nexport function formatDisplayDate(dateStr: string, locale: ChartLocale): string {\n\tconst d = parseDate(dateStr);\n\treturn d.toLocaleDateString(locale.code, {year: 'numeric', month: '2-digit', day: '2-digit', timeZone: 'UTC'});\n}\n","export type TimeScale = 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year';\n\nexport type ScaleConfig = {\n\t/** Pixel width of one column unit */\n\tcolumnWidth: number;\n\t/** Milliseconds per column unit */\n\tmsPerColumn: number;\n\theaderFormat: TimeScale;\n};\n\nconst H = 3_600_000;\nconst D = 86_400_000;\n\nexport const SCALE_CONFIGS: Record<TimeScale, ScaleConfig> = {\n\thour: {columnWidth: 60, msPerColumn: H, headerFormat: 'hour'},\n\tday: {columnWidth: 72, msPerColumn: D, headerFormat: 'day'},\n\tweek: {columnWidth: 120, msPerColumn: 7 * D, headerFormat: 'week'},\n\tmonth: {columnWidth: 160, msPerColumn: 30 * D, headerFormat: 'month'},\n\tquarter: {columnWidth: 220, msPerColumn: 91 * D, headerFormat: 'quarter'},\n\tyear: {columnWidth: 280, msPerColumn: 365 * D, headerFormat: 'year'},\n};\n\n/**\n * Snaps a date to the column boundary for the provided scale.\n * All operations use UTC semantics.\n * The week boundary respects the optional `weekStartsOn` override (0=Sun, 1=Mon, 6=Sat).\n *\n * @param date - The date to snap.\n * @param scale - The target {@link TimeScale}.\n * @param weekStartsOn - First day of the week (`0`-Sun, `1`-Mon, `6`-Sat). Defaults to `1` (Monday).\n * @returns A new `Date` snapped to the column boundary.\n */\nexport function snapToScaleBoundary(date: Date, scale: TimeScale, weekStartsOn: 0 | 1 | 6 = 1): Date {\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()));\n\t\t}\n\t\tcase 'day': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\t\t}\n\t\tcase 'week': {\n\t\t\tconst d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n\t\t\tconst dow = d.getUTCDay();\n\t\t\tconst offset = (((dow - weekStartsOn) % 7) + 7) % 7;\n\t\t\td.setUTCDate(d.getUTCDate() - offset);\n\t\t\treturn d;\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n\t\t}\n\t\tcase 'quarter': {\n\t\t\tconst month = date.getUTCMonth();\n\t\t\tconst quarterStartMonth = Math.floor(month / 3) * 3;\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), quarterStartMonth, 1));\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), 0, 1));\n\t\t}\n\t}\n}\n\n/**\n * Returns the next column boundary from a boundary-aligned date.\n * Month/quarter/year use true calendar stepping (not fixed-day approximations).\n *\n * @param date - A boundary-aligned date.\n * @param scale - The target {@link TimeScale}.\n * @returns The next boundary date.\n */\nexport function nextScaleBoundary(date: Date, scale: TimeScale): Date {\n\tswitch (scale) {\n\t\tcase 'hour': {\n\t\t\treturn new Date(date.getTime() + H);\n\t\t}\n\t\tcase 'day': {\n\t\t\treturn new Date(date.getTime() + D);\n\t\t}\n\t\tcase 'week': {\n\t\t\treturn new Date(date.getTime() + 7 * D);\n\t\t}\n\t\tcase 'month': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1));\n\t\t}\n\t\tcase 'quarter': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 3, 1));\n\t\t}\n\t\tcase 'year': {\n\t\t\treturn new Date(Date.UTC(date.getUTCFullYear() + 1, 0, 1));\n\t\t}\n\t}\n}\n\n/**\n * Rounds a date up to the end boundary of the containing scale bucket.\n * If the date is already on a boundary, it is returned unchanged.\n *\n * @param date - The date to round.\n * @param scale - The target {@link TimeScale}.\n * @param weekStartsOn - First day of the week (`0`-Sun, `1`-Mon, `6`-Sat). Defaults to `1` (Monday).\n * @returns A boundary-aligned date at or after the input.\n */\nexport function ceilToScaleBoundary(date: Date, scale: TimeScale, weekStartsOn: 0 | 1 | 6 = 1): Date {\n\tconst start = snapToScaleBoundary(date, scale, weekStartsOn);\n\tif (start.getTime() === date.getTime()) {\n\t\treturn start;\n\t}\n\treturn nextScaleBoundary(start, scale);\n}\n","import {SCALE_CONFIGS} from './scale.ts';\nimport {type TimeScale} from './scale.ts';\n\nexport type PixelMapper = {\n\t/** Date → x pixel offset from viewport start */\n\ttoX: (date: Date) => number;\n\t/** x pixel offset → Date */\n\ttoDate: (x: number) => Date;\n\t/** Days → pixel width */\n\tdurationDaysToWidth: (days: number) => number;\n\t/** Pixel width → days (float) */\n\twidthToDurationDays: (px: number) => number;\n\t/** The origin timestamp used for this mapper */\n\toriginMs: number;\n\t/** Pixel width of one column unit */\n\tcolumnWidth: number;\n};\n\n/**\n * Creates a stateless pixel mapper for the given scale and viewport start.\n * All conversions are O(1) arithmetic — safe to call in tight loops.\n *\n * @param scale - The active {@link TimeScale}.\n * @param viewportStart - The leftmost date visible in the viewport.\n * @returns A {@link PixelMapper} configured for the given viewport.\n */\nexport function createPixelMapper(scale: TimeScale, viewportStart: Date): PixelMapper {\n\tconst {columnWidth, msPerColumn} = SCALE_CONFIGS[scale];\n\tconst originMs = viewportStart.getTime();\n\tconst pxPerMs = columnWidth / msPerColumn;\n\tconst msPerPx = msPerColumn / columnWidth;\n\tconst msPerDay = 86_400_000;\n\n\treturn {\n\t\toriginMs,\n\t\tcolumnWidth,\n\t\ttoX(date: Date): number {\n\t\t\treturn (date.getTime() - originMs) * pxPerMs;\n\t\t},\n\t\ttoDate(x: number): Date {\n\t\t\treturn new Date(originMs + x * msPerPx);\n\t\t},\n\t\tdurationDaysToWidth(days: number): number {\n\t\t\treturn days * msPerDay * pxPerMs;\n\t\t},\n\t\twidthToDurationDays(px: number): number {\n\t\t\treturn (px * msPerPx) / msPerDay;\n\t\t},\n\t};\n}\n","import {type TaskNode} from '../domain/tree.ts';\nimport {type PixelMapper} from './pixelMapper.ts';\nimport {parseDate, addHours, getRangeDays} from '../domain/dateMath.ts';\n\nexport const DENSITY = {\n\trowHeight: 44,\n\tbarHeight: 28,\n\tmilestoneSize: 20,\n} as const;\n\nexport const ROW_HEIGHT = DENSITY.rowHeight;\nexport const BAR_HEIGHT = DENSITY.barHeight;\nexport const BAR_Y_OFFSET = (ROW_HEIGHT - BAR_HEIGHT) / 2;\nexport const MILESTONE_SIZE = DENSITY.milestoneSize;\n/** Half-width of a milestone diamond */\nexport const MILESTONE_HALF = MILESTONE_SIZE / 2;\n\nexport type BarLayout = {\n\ttaskId: number;\n\t/** Left edge x in timeline coordinates */\n\tx: number;\n\t/** Top edge y in content coordinates */\n\ty: number;\n\twidth: number;\n\theight: number;\n\tprogressWidth: number;\n\tkind: 'task' | 'project' | 'milestone';\n\trowIndex: number;\n\t/** Center x; identical to x + width/2 or x for milestones */\n\tcenterX: number;\n\tcenterY: number;\n};\n\n/**\n * Computes pixel-space layout for all visible task rows.\n * Returns a map keyed by task id for O(1) lookup during link routing.\n *\n * @param rows - The flattened, visible {@link TaskNode} rows.\n * @param mapper - The {@link PixelMapper} for coordinate conversion.\n * @returns A `Map` from task ID to its computed {@link BarLayout}.\n */\nexport function computeLayout(rows: TaskNode[], mapper: PixelMapper): Map<number, BarLayout> {\n\tconst result = new Map<number, BarLayout>();\n\n\tfor (let i = 0; i < rows.length; i++) {\n\t\tconst task = rows[i];\n\t\tif (task === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst start = parseDate(task.startDate);\n\t\tconst x = mapper.toX(start);\n\t\tconst y = i * ROW_HEIGHT + BAR_Y_OFFSET;\n\t\tconst centerY = i * ROW_HEIGHT + ROW_HEIGHT / 2;\n\n\t\tif (task.kind === 'milestone') {\n\t\t\tresult.set(task.id, {\n\t\t\t\ttaskId: task.id,\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\twidth: 0,\n\t\t\t\theight: BAR_HEIGHT,\n\t\t\t\tprogressWidth: 0,\n\t\t\t\tkind: 'milestone',\n\t\t\t\trowIndex: i,\n\t\t\t\tcenterX: x,\n\t\t\t\tcenterY,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst end = parseDate(task.endDate);\n\t\tconst days = getRangeDays(start, end);\n\t\tconst width = Math.max(mapper.durationDaysToWidth(days), 4);\n\t\tconst progressWidth = width * Math.min(1, Math.max(0, (task.percentComplete ?? 0) / 100));\n\n\t\tresult.set(task.id, {\n\t\t\ttaskId: task.id,\n\t\t\tx,\n\t\t\ty,\n\t\t\twidth,\n\t\t\theight: BAR_HEIGHT,\n\t\t\tprogressWidth,\n\t\t\tkind: task.kind,\n\t\t\trowIndex: i,\n\t\t\tcenterX: x + width / 2,\n\t\t\tcenterY,\n\t\t});\n\t}\n\n\treturn result;\n}\n\n/**\n * Computes the total pixel height of all rows.\n *\n * @param rowCount - The number of visible rows.\n * @returns The total pixel height (`rowCount * ROW_HEIGHT`).\n */\nexport function totalContentHeight(rowCount: number): number {\n\treturn rowCount * ROW_HEIGHT;\n}\n\n/**\n * Derives viewport bounds from task data with padding.\n *\n * @param tasks - The task nodes to derive bounds from.\n * @param paddingHours - Extra hours added before the earliest start and after the latest end. Defaults to `48`.\n * @returns A tuple `[start, end]` of UTC midnight `Date` instances.\n */\nexport function deriveViewport(tasks: TaskNode[], paddingHours = 48): [Date, Date] {\n\tif (tasks.length === 0) {\n\t\tconst now = new Date();\n\t\treturn [now, addHours(now, 720)];\n\t}\n\n\tlet minMs = Infinity;\n\tlet maxMs = -Infinity;\n\n\tfor (const task of tasks) {\n\t\tconst start = parseDate(task.startDate);\n\t\tif (start.getTime() < minMs) {\n\t\t\tminMs = start.getTime();\n\t\t}\n\t\tif (task.kind !== 'milestone') {\n\t\t\tconst end = parseDate(task.endDate);\n\t\t\tif (end.getTime() > maxMs) {\n\t\t\t\tmaxMs = end.getTime();\n\t\t\t}\n\t\t} else if (start.getTime() > maxMs) {\n\t\t\tmaxMs = start.getTime();\n\t\t}\n\t}\n\n\treturn [addHours(new Date(minMs), -paddingHours), addHours(new Date(maxMs), paddingHours)];\n}\n","import {type ZodLinkInferred as Link, type LinkType} from '../validation/schemas.ts';\nimport {type BarLayout} from '../timeline/layoutEngine.ts';\nimport {MILESTONE_HALF, ROW_HEIGHT} from '../timeline/layoutEngine.ts';\n\nexport type Point = {x: number; y: number};\n\nexport type RoutedLink = {\n\tlinkId: number;\n\tsourceTaskId: number;\n\ttargetTaskId: number;\n\ttype: LinkType;\n\t/** Ordered vertices of the orthogonal polyline (source → target). */\n\tpoints: Point[];\n};\n\n/** px gap before/after bar for routing clearance and arrow approach */\nconst TURN_MARGIN = 24;\n\n/** px vertical offset below the bar row for same-row loop detours */\nconst SAME_ROW_DETOUR = 24;\n\n/** Segments shorter than this (px) are collapsed before stroking */\nconst STUB_THRESHOLD = 2;\n\n/**\n * Removes consecutive points whose Euclidean distance is below {@link STUB_THRESHOLD}.\n * The first point is always kept. This prevents near‑zero‑length segments from\n * appearing as visible stubs near the arrowhead.\n *\n * @param points - The ordered vertex list.\n * @returns A filtered copy, guaranteed to contain at least the first point.\n */\nfunction collapseStubs(points: Point[]): Point[] {\n\tconst out: Point[] = [];\n\tfor (const pt of points) {\n\t\tconst last = out.at(-1);\n\t\tif (last === undefined || Math.hypot(pt.x - last.x, pt.y - last.y) >= STUB_THRESHOLD) {\n\t\t\tout.push(pt);\n\t\t}\n\t}\n\treturn out;\n}\n\n// ─── Anchor point helpers ────────────────────────────────────────────────────────\n\n/**\n * True when the dependency arrow enters the target on its **left** edge (FS, SS).\n * False when the arrow enters on the target's **right** edge (FF, SF).\n *\n * The arrowhead uses SVG `orient=\"auto\"` so it rotates to match the direction\n * of the **last** path segment. Therefore:\n *\n * - Left-entry → last segment must travel **RIGHT** (penultimate.x < tx).\n * - Right-entry → last segment must travel **LEFT** (penultimate.x > tx).\n *\n * @param type - The link type.\n * @returns `true` for FS / SS, `false` for FF / SF.\n */\nfunction isLeftEntry(type: Link['type']): boolean {\n\treturn type === 'FS' || type === 'SS';\n}\n\n/**\n * True when the link exits the source bar on its **right** edge (FS, FF).\n * False when it exits on the **left** edge (SS, SF).\n *\n * The first step after the source anchor should move **away** from the bar,\n * **not** into it. This means:\n *\n * - Exit‑right → first horizontal segment goes RIGHT (+TURN_MARGIN).\n * - Exit‑left → first horizontal segment goes LEFT (-TURN_MARGIN).\n *\n * @param type - The link type.\n * @returns `true` for FS / FF, `false` for SS / SF.\n */\nfunction isExitRight(type: Link['type']): boolean {\n\treturn type === 'FS' || type === 'FF';\n}\n\n/**\n * Computes anchor points for the given link type.\n *\n * | Type | Source anchor (`sx`) | Target anchor (`tx`) |\n * |------|-----------------------------|-------------------------------|\n * | FS | right edge of source | left edge of target |\n * | SS | left edge of source | left edge of target |\n * | FF | right edge of source | right edge of target |\n * | SF | left edge of source | right edge of target |\n *\n * Milestone offsets are applied automatically: ± {@link MILESTONE_HALF} replaces\n * ± width for zero‑width milestones.\n *\n * @param type - The link type determining start/end anchor points.\n * @param src - The source bar layout.\n * @param tgt - The target bar layout.\n * @returns Anchor x coordinates `{sx, tx}`.\n * @throws {Error} if the link type is not handled (exhaustiveness guard).\n */\nfunction getAnchors(type: Link['type'], src: BarLayout, tgt: BarLayout): {sx: number; tx: number} {\n\tconst srcRight = src.kind === 'milestone' ? src.x + MILESTONE_HALF : src.x + src.width;\n\tconst srcLeft = src.kind === 'milestone' ? src.x - MILESTONE_HALF : src.x;\n\tconst tgtRight = tgt.kind === 'milestone' ? tgt.x + MILESTONE_HALF : tgt.x + tgt.width;\n\tconst tgtLeft = tgt.kind === 'milestone' ? tgt.x - MILESTONE_HALF : tgt.x;\n\n\tswitch (type) {\n\t\tcase 'FS': {\n\t\t\treturn {sx: srcRight, tx: tgtLeft};\n\t\t}\n\t\tcase 'SS': {\n\t\t\treturn {sx: srcLeft, tx: tgtLeft};\n\t\t}\n\t\tcase 'FF': {\n\t\t\treturn {sx: srcRight, tx: tgtRight};\n\t\t}\n\t\tcase 'SF': {\n\t\t\treturn {sx: srcLeft, tx: tgtRight};\n\t\t}\n\t\tdefault: {\n\t\t\tconst _exhaustive: never = type;\n\t\t\tthrow new Error(`Unhandled link type: ${String(_exhaustive)}`);\n\t\t}\n\t}\n}\n\n// ─── Same-row routing ────────────────────────────────────────────────────────────\n\n/**\n * Routes a link whose source and target rows are within 1 px of each other.\n *\n * **Direct‑line optimisation**\n * A plain horizontal segment is only used when it is non‑degenerate (`sx ≠ tx`)\n * AND the arrowhead direction is visually correct:\n *\n * | Entry side | Condition | Arrow direction |\n * |-----------|-----------|----------------|\n * | left | `sx < tx` | → RIGHT ✓ |\n * | right | `sx > tx` | ← LEFT ✓ |\n *\n * Otherwise a 6‑vertex detour is drawn so that the last segment approaches\n * the target from the correct side. By default the detour goes **below** the\n * bars; pass `above = true` when headroom is insufficient below.\n *\n * @param sx - Source anchor x.\n * @param sy - Source row center y.\n * @param tx - Target anchor x.\n * @param ty - Target row center y.\n * @param leftEntry - Whether the link enters the target on its left edge.\n * @param exitRight - Whether the link exits the source on its right edge.\n * @param above - Route the detour above the bar row instead of below (default `false`).\n * @returns An ordered array of {@link Point} vertices.\n */\nfunction routeSameRow(sx: number, sy: number, tx: number, ty: number, leftEntry: boolean, exitRight: boolean, above = false): Point[] {\n\t// Direct horizontal line when non‑degenerate and arrow direction is correct\n\tif (Math.abs(sx - tx) >= STUB_THRESHOLD) {\n\t\tconst directOk = (leftEntry && sx < tx) || (!leftEntry && sx > tx);\n\t\tif (directOk) {\n\t\t\treturn [\n\t\t\t\t{x: sx, y: sy},\n\t\t\t\t{x: tx, y: ty},\n\t\t\t];\n\t\t}\n\t}\n\n\t// ── Loop detour ──\n\t//\n\t// The path steps away from the source edge, drops to the detour level,\n\t// crosses horizontally to an approach point on the correct side of the\n\t// target, then returns to the target entry point.\n\t//\n\t// left‑entry approach right‑entry approach\n\t// ────────────────── ────────────────────\n\t// anchor sx → tx sx → tx\n\t// exit +dir exit +dir\n\t// │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │\n\t// ▼ │ │ │ │ │ │ │ ▼ │ │ │ │ │ │ │\n\t// ┌──┐│ │ │ │ │ │ │ ┌──┐│ │ │ │ │ │ │\n\t// │ ││ │ │ │ │ │ │ │ ││ │ │ │ │ │ │ (bar row)\n\t// │▐▌││ │ │ │ │ │ │ │▐▌││ │ │ │ │ │ │\n\t// └──┘│ │ │ │ │ │ │ └──┘│ │ │ │ │ │ │\n\t// │ │ │ │ │ │ │ │ │ │ │ │ │ │\n\t// detour ══╪═╪═╪═╪══════► ════════════╪═╪═╪═►\n\t// │ │ │ │ │ │ │ │ │ │ │ │ │ │\n\t// │ │ │ │ │ ▼ ► │ │ │ │ │ │ ▼\n\t// │ │ │ │ └──┐│ │ │ │ │ │ └──┐\n\t// │ │ │ │ │▐▌│ │ │ │ │ │ │▐▌│ (target)\n\t// │ │ │ │ └──┘│ │ │ │ │ │ └──┘\n\t//\n\t// points 6 6\n\t// approach tx - TURN_MARGIN tx + TURN_MARGIN\n\t// last seg → RIGHT → LEFT\n\n\tconst exitDir = exitRight ? TURN_MARGIN : -TURN_MARGIN;\n\tconst detourY = sy + (above ? -SAME_ROW_DETOUR : SAME_ROW_DETOUR);\n\tconst approachX = leftEntry ? tx - TURN_MARGIN : tx + TURN_MARGIN;\n\n\treturn [\n\t\t{x: sx, y: sy},\n\t\t{x: sx + exitDir, y: sy},\n\t\t{x: sx + exitDir, y: detourY},\n\t\t{x: approachX, y: detourY},\n\t\t{x: approachX, y: ty},\n\t\t{x: tx, y: ty},\n\t];\n}\n\n// ─── Multi-row routing ───────────────────────────────────────────────────────────\n\n/**\n * Routes a link between **different** rows using an orthogonal path.\n *\n * 1. Step **away** from the source bar to the crossover x (`crossX`).\n * 2. Travel **vertically** to the midpoint between rows (`midY`).\n * 3. Travel **horizontally** to the approach point on the correct side\n * of the target.\n * 4. Travel **vertically** to the target row (`ty`).\n * 5. Final segment to the target entry point (`tx`).\n *\n * The crossover x is clamped so the path never doubles back past both bars.\n * When exit and entry are on the **same** side (SS / FF) the exit-side step\n * is limited to the approach x, avoiding a wide U‑shape.\n *\n * The approach point is chosen so the last segment travels in the arrow\n * direction demanded by the entry side:\n *\n * - Left‑entry (FS, SS): approach from the **left** → `tx - TURN_MARGIN`\n * Last segment goes RIGHT.\n * - Right‑entry (FF, SF): approach from the **right** → `tx + TURN_MARGIN`\n * Last segment goes LEFT.\n *\n * left‑entry (FS / SS) right‑entry (FF / SF)\n * ───────────────────── ─────────────────────\n * sx ●────────────────► sx ●────────────────►\n * exitDir exitDir\n * │ │\n * │ midY │ midY\n * ▼ ════════════════════► ▼ ════════════════════►\n * │ │\n * │ │\n * ▼ approachFromLeft ▼ approachFromRight\n * ●────────────────► ◄────────────────●\n * tx tx\n *\n * @param sx - Source anchor x.\n * @param sy - Source row center y.\n * @param tx - Target anchor x.\n * @param ty - Target row center y.\n * @param leftEntry - Whether the link enters the target on its left edge.\n * @param exitRight - Whether the link exits the source on its right edge.\n * @returns An ordered array of {@link Point} vertices.\n */\nfunction routeMultiRow(sx: number, sy: number, tx: number, ty: number, leftEntry: boolean, exitRight: boolean): Point[] {\n\tconst rowsApart = Math.round(Math.abs(sy - ty) / ROW_HEIGHT);\n\tconst midY = rowsApart % 2 === 0 ? (sy + ty) / 2 + ROW_HEIGHT / 2 : (sy + ty) / 2;\n\tconst approachX = leftEntry ? tx - TURN_MARGIN : tx + TURN_MARGIN;\n\tconst crossX = exitRight ? Math.max(sx + TURN_MARGIN, approachX) : Math.min(sx - TURN_MARGIN, approachX);\n\n\treturn [\n\t\t{x: sx, y: sy},\n\t\t{x: crossX, y: sy},\n\t\t{x: crossX, y: midY},\n\t\t{x: approachX, y: midY},\n\t\t{x: approachX, y: ty},\n\t\t{x: tx, y: ty},\n\t];\n}\n\n// ─── Entry point ─────────────────────────────────────────────────────────────────\n\n/**\n * Produces the vertex list for an orthogonal connector between source and target.\n *\n * ## Anchor points (sx / tx)\n *\n * | Type | Source anchor (`sx`) | Target anchor (`tx`) |\n * |------|-----------------------------|-------------------------------|\n * | FS | right edge of source | left edge of target |\n * | SS | left edge of source | left edge of target |\n * | FF | right edge of source | right edge of target |\n * | SF | left edge of source | right edge of target |\n *\n * Milestone offsets are applied automatically: ± {@link MILESTONE_HALF} replaces\n * ± width for zero‑width milestones.\n *\n * ## Routing strategy\n *\n * **Same row** (|sy − ty| < 1 px):\n * - Direct horizontal line when non‑degenerate **and** the arrow direction\n * naturally points **into** the target (see {@link routeSameRow}).\n * - Otherwise a 6‑vertex detour below the bars is drawn.\n *\n * **Different rows**: always a 6‑vertex orthogonal path that steps away from\n * the source, passes through the midpoint between rows, and approaches the\n * target from the correct side (see {@link routeMultiRow}).\n *\n * ## Arrowhead direction guarantee\n *\n * The SVG `marker-end` uses `orient=\"auto\"`, so the arrow rotates to match\n * the last segment. This function ensures the last segment always travels\n * **into** the target on the semantically correct edge:\n *\n * | Entry side | Target edge | Last segment direction |\n * |-----------|-------------|-----------------------|\n * | left | left edge | → RIGHT |\n * | right | right edge | ← LEFT |\n *\n * @param type - The link type determining start/end anchor points.\n * @param src - The source bar layout.\n * @param tgt - The target bar layout.\n * @returns An ordered array of {@link Point} vertices.\n */\nfunction route(type: Link['type'], src: BarLayout, tgt: BarLayout): Point[] {\n\tconst {sx, tx} = getAnchors(type, src, tgt);\n\tconst sy = src.centerY;\n\tconst ty = tgt.centerY;\n\n\tconst leftEntry = isLeftEntry(type);\n\tconst exitRight = isExitRight(type);\n\n\tconst raw = Math.abs(sy - ty) < 1 ? routeSameRow(sx, sy, tx, ty, leftEntry, exitRight) : routeMultiRow(sx, sy, tx, ty, leftEntry, exitRight);\n\n\treturn collapseStubs(raw);\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────────\n\n/**\n * Computes orthogonal routing for all dependency links.\n * Links whose source or target is not in the layout map are skipped silently\n * (e.g. when the row is collapsed).\n *\n * @param links - The dependency links to route.\n * @param layouts - A map from task ID to its computed {@link BarLayout}.\n * @returns An array of {@link RoutedLink} objects with computed vertex paths.\n */\nexport function routeLinks(links: Link[], layouts: Map<number, BarLayout>): RoutedLink[] {\n\treturn links\n\t\t.map((link) => {\n\t\t\tconst src = layouts.get(link.source);\n\t\t\tconst tgt = layouts.get(link.target);\n\t\t\tif (src === undefined || tgt === undefined) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlinkId: link.id,\n\t\t\t\tsourceTaskId: link.source,\n\t\t\t\ttargetTaskId: link.target,\n\t\t\t\ttype: link.type,\n\t\t\t\tpoints: route(link.type, src, tgt),\n\t\t\t};\n\t\t})\n\t\t.filter((r): r is RoutedLink => r !== null);\n}\n","import {z} from 'zod';\n\nexport const LinkTypeSchema = z.enum(['FS', 'SS', 'FF', 'SF']);\nexport const TaskKindSchema = z.enum(['task', 'project', 'milestone']);\nconst SpecialDayKindSchema = z.enum(['holiday', 'custom']);\n\n/** @internal */\nexport const SpecialDaySchema = z.object({\n\t/** ISO date: YYYY-MM-DD */\n\tdate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\tkind: SpecialDayKindSchema,\n\tlabel: z.string().min(1).optional(),\n\tclassName: z.string().min(1).optional(),\n});\n\nconst taskBase = {\n\t/** Unique positive integer identifier for the task. */\n\tid: z.number().int().positive(),\n\t/** Display name / label of the task. */\n\ttext: z.string().min(1),\n\t/** ISO date: YYYY-MM-DD */\n\tstartDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\t/** Optional id of the parent task. When set, this task is a child in the hierarchy. */\n\tparent: z.number().int().positive().optional(),\n\t/** Optional CSS color value for the task bar. Overrides the default color assignment. */\n\tcolor: z.string().optional(),\n\t/** When `true`, the task bar cannot be dragged or resized. */\n\treadonly: z.boolean().optional(),\n\t/** Optional arbitrary metadata for consumer use. Preserved in the parsed output. */\n\tdata: z.record(z.string(), z.unknown()).optional(),\n};\n\n/** @internal */\nconst TaskLeafSchema = z\n\t.object({\n\t\t...taskBase,\n\t\tkind: z.literal('task'),\n\t\t/** ISO date: YYYY-MM-DD */\n\t\tendDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\t\t/** 0–100 completion percentage (integer). */\n\t\tpercentComplete: z.number().int().min(0).max(100).default(0),\n\t})\n\t.refine((t) => t.endDate >= t.startDate, {message: 'endDate must be on or after startDate', path: ['endDate']});\n\n/** @internal */\nconst TaskProjectSchema = z\n\t.object({\n\t\t...taskBase,\n\t\tkind: z.literal('project'),\n\t\t/** ISO date: YYYY-MM-DD */\n\t\tendDate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/u, 'Expected YYYY-MM-DD'),\n\t\t/** 0–100 completion percentage (integer). */\n\t\tpercentComplete: z.number().int().min(0).max(100).default(0),\n\t\t/**\n\t\t * Initial expanded state for tree hierarchy.\n\t\t * When `false`, children of this task are hidden on initial render.\n\t\t *\n\t\t * @default true\n\t\t */\n\t\topen: z.boolean().default(true),\n\t})\n\t.refine((t) => t.endDate >= t.startDate, {message: 'endDate must be on or after startDate', path: ['endDate']});\n\n/** @internal */\nconst TaskMilestoneSchema = z.object({\n\t...taskBase,\n\tkind: z.literal('milestone'),\n});\n\nconst TaskSchema = z.discriminatedUnion('kind', [TaskLeafSchema, TaskProjectSchema, TaskMilestoneSchema]);\n\nconst LinkSchema = z\n\t.object({\n\t\t/** Unique positive integer identifier for the dependency link. */\n\t\tid: z.number().int().positive(),\n\t\t/** The `id` of the predecessor task (the task that drives the dependency). */\n\t\tsource: z.number().int().positive(),\n\t\t/** The `id` of the successor task (the task that depends on the predecessor). */\n\t\ttarget: z.number().int().positive(),\n\t\t/**\n\t\t * Dependency type.\n\t\t *\n\t\t * - `'FS'` — Finish-to-start: successor starts after predecessor finishes.\n\t\t * - `'SS'` — Start-to-start: successor starts at the same time as predecessor.\n\t\t * - `'FF'` — Finish-to-finish: successor finishes at the same time as predecessor.\n\t\t * - `'SF'` — Start-to-finish: successor finishes after predecessor starts.\n\t\t *\n\t\t * @default 'FS'\n\t\t */\n\t\ttype: LinkTypeSchema.default('FS'),\n\t\t/** When `true`, the link cannot be modified or deleted through the UI. */\n\t\treadonly: z.boolean().optional(),\n\t\t/** Optional arbitrary metadata for consumer use. Preserved in the parsed output. */\n\t\tdata: z.record(z.string(), z.unknown()).optional(),\n\t})\n\t.refine((l) => l.source !== l.target, {\n\t\tmessage: 'A link cannot connect a task to itself',\n\t\tpath: ['target'],\n\t});\n\n/** @internal */\nexport const GanttInputSchema = z\n\t.object({\n\t\t/** Array of task objects. At least one task is required. */\n\t\ttasks: z.array(TaskSchema).min(1),\n\t\t/** Optional array of dependency link objects. Defaults to empty array. */\n\t\tlinks: z.array(LinkSchema).default([]),\n\t})\n\t.superRefine((data, ctx) => {\n\t\t// Duplicate task IDs\n\t\tconst taskIds = new Set<number>();\n\t\tfor (let i = 0; i < data.tasks.length; i++) {\n\t\t\tconst task = data.tasks[i];\n\t\t\tif (task !== undefined) {\n\t\t\t\tif (taskIds.has(task.id)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Duplicate task id: ${task.id}`,\n\t\t\t\t\t\tpath: ['tasks', i, 'id'],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\ttaskIds.add(task.id);\n\t\t\t}\n\t\t}\n\n\t\t// Duplicate link IDs\n\t\tconst linkIds = new Set<number>();\n\t\tfor (let i = 0; i < data.links.length; i++) {\n\t\t\tconst link = data.links[i];\n\t\t\tif (link !== undefined) {\n\t\t\t\tif (linkIds.has(link.id)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Duplicate link id: ${link.id}`,\n\t\t\t\t\t\tpath: ['links', i, 'id'],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tlinkIds.add(link.id);\n\t\t\t}\n\t\t}\n\n\t\t// Duplicate (source, target) pairs\n\t\tconst pairKeys = new Set<string>();\n\t\tfor (let i = 0; i < data.links.length; i++) {\n\t\t\tconst link = data.links[i];\n\t\t\tif (link !== undefined) {\n\t\t\t\tconst key = `${link.source}:${link.target}`;\n\t\t\t\tif (pairKeys.has(key)) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: 'custom',\n\t\t\t\t\t\tmessage: `Duplicate link pair: source=${link.source} target=${link.target}`,\n\t\t\t\t\t\tpath: ['links', i],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tpairKeys.add(key);\n\t\t\t}\n\t\t}\n\t});\n\n// ─── Internal zod-inferred types (runtime shapes, include data?: Record<string, unknown>) ───\n\n/** @internal */\nexport type ZodTaskInferred = z.infer<typeof TaskSchema>;\n/** @internal */\nexport type ZodLinkInferred = z.infer<typeof LinkSchema>;\n\n// ─── Public generic types ───\n\n/**\n * A task in the Gantt chart — discriminated by `kind` into leaf tasks,\n * summary projects, and milestones.\n *\n * @param TData - The type of the optional `data` property. Defaults to `never`,\n * which omits the `data` property from the type. Specify a concrete type to enable\n * compile-time-checked task data in both input and callback payloads.\n *\n * @example\n * ```ts\n * // Default: no `data` property\n * const task: Task = { id: 1, text: 'Build', startDate: '2026-01-01', endDate: '2026-01-03', kind: 'task' };\n *\n * // With typed data\n * interface TaskMeta { priority: number; label: string }\n * const typedTask: Task<TaskMeta> = {\n * id: 1, text: 'Build', startDate: '2026-01-01', endDate: '2026-01-03',\n * kind: 'task', data: { priority: 1, label: 'critical' }\n * };\n * ```\n */\nexport type Task<TData = never> =\n\t| {\n\t\t\tid: number;\n\t\t\ttext: string;\n\t\t\tstartDate: string;\n\t\t\tparent?: number | undefined;\n\t\t\tcolor?: string | undefined;\n\t\t\treadonly?: boolean | undefined;\n\t\t\tdata?: unknown;\n\t\t\tkind: 'task';\n\t\t\tendDate: string;\n\t\t\tpercentComplete: number;\n\t }\n\t| {\n\t\t\tid: number;\n\t\t\ttext: string;\n\t\t\tstartDate: string;\n\t\t\tparent?: number | undefined;\n\t\t\tcolor?: string | undefined;\n\t\t\treadonly?: boolean | undefined;\n\t\t\tdata?: unknown;\n\t\t\tkind: 'project';\n\t\t\tendDate: string;\n\t\t\tpercentComplete: number;\n\t\t\topen: boolean;\n\t }\n\t| {\n\t\t\tid: number;\n\t\t\ttext: string;\n\t\t\tstartDate: string;\n\t\t\tparent?: number | undefined;\n\t\t\tcolor?: string | undefined;\n\t\t\treadonly?: boolean | undefined;\n\t\t\tdata?: unknown;\n\t\t\tkind: 'milestone';\n\t } extends infer _U\n\t? _U extends unknown\n\t\t? Omit<_U, 'data'> &\n\t\t\t\t([TData] extends [never]\n\t\t\t\t\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\t\t\t\t\tRecord<never, never>\n\t\t\t\t\t: {data?: TData | undefined})\n\t\t: never\n\t: never;\n\n/**\n * A dependency link between two tasks.\n *\n * @param TData - The type of the optional `data` property. Defaults to `never`.\n */\nexport type Link<TData = never> = {\n\tid: number;\n\tsource: number;\n\ttarget: number;\n\ttype: LinkType;\n\treadonly?: boolean | undefined;\n} & ([TData] extends [never]\n\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\tRecord<never, never>\n\t: {data?: TData | undefined});\n\n/**\n * The complete input data for the chart.\n *\n * @param TTaskData - The type of the `data` property on tasks. Defaults to `never`.\n * @param TLinkData - The type of the `data` property on links. Defaults to `never`.\n */\nexport type GanttInput<TTaskData = never, TLinkData = never> = {\n\ttasks: Task<TTaskData>[];\n\tlinks: Link<TLinkData>[];\n};\n\n/** @internal */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport type _GanttInputZod = z.infer<typeof GanttInputSchema>;\n\n/**\n * The raw input shape that consumers pass to {@link GanttChart.update}.\n *\n * Fields with defaults in the schema (e.g. `percentComplete`, `type`) remain optional here.\n *\n * @param TTaskData - The type of the `data` property on tasks. Defaults to `never`.\n * @param TLinkData - The type of the `data` property on links. Defaults to `never`.\n */\nexport type GanttInputRaw<TTaskData = never, TLinkData = never> = {\n\ttasks: readonly (\n\t\t| {\n\t\t\t\tid: number;\n\t\t\t\ttext: string;\n\t\t\t\tstartDate: string;\n\t\t\t\tparent?: number | undefined;\n\t\t\t\tcolor?: string | undefined;\n\t\t\t\treadonly?: boolean | undefined;\n\t\t\t\tdata?: unknown;\n\t\t\t\tkind: 'task';\n\t\t\t\tendDate: string;\n\t\t\t\tpercentComplete?: number | undefined;\n\t\t }\n\t\t| {\n\t\t\t\tid: number;\n\t\t\t\ttext: string;\n\t\t\t\tstartDate: string;\n\t\t\t\tparent?: number | undefined;\n\t\t\t\tcolor?: string | undefined;\n\t\t\t\treadonly?: boolean | undefined;\n\t\t\t\tdata?: unknown;\n\t\t\t\tkind: 'project';\n\t\t\t\tendDate: string;\n\t\t\t\tpercentComplete?: number | undefined;\n\t\t\t\topen?: boolean | undefined;\n\t\t }\n\t\t| {\n\t\t\t\tid: number;\n\t\t\t\ttext: string;\n\t\t\t\tstartDate: string;\n\t\t\t\tparent?: number | undefined;\n\t\t\t\tcolor?: string | undefined;\n\t\t\t\treadonly?: boolean | undefined;\n\t\t\t\tdata?: unknown;\n\t\t\t\tkind: 'milestone';\n\t\t } extends infer _RU\n\t\t? _RU extends unknown\n\t\t\t? Omit<_RU, 'data'> &\n\t\t\t\t\t([TTaskData] extends [never]\n\t\t\t\t\t\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\t\t\t\t\t\tRecord<never, never>\n\t\t\t\t\t\t: {data?: TTaskData | undefined})\n\t\t\t: never\n\t\t: never)[];\n\tlinks?: readonly ({\n\t\tid: number;\n\t\tsource: number;\n\t\ttarget: number;\n\t\ttype?: LinkType | undefined;\n\t\treadonly?: boolean | undefined;\n\t} & ([TLinkData] extends [never]\n\t\t? // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n\t\t\tRecord<never, never>\n\t\t: {data?: TLinkData | undefined}))[];\n};\n/** Allowed dependency link type values: `'FS'`, `'SS'`, `'FF'`, or `'SF'`. */\nexport type LinkType = 'FS' | 'SS' | 'FF' | 'SF';\n/** Allowed task kind values: `'task'`, `'project'`, or `'milestone'`. */\nexport type TaskKind = 'task' | 'project' | 'milestone';\nexport type SpecialDayKind = 'holiday' | 'custom';\nexport type SpecialDay = {\n\t/** ISO date: YYYY-MM-DD */\n\tdate: string;\n\tkind: SpecialDayKind;\n\tlabel?: string | undefined;\n\tclassName?: string | undefined;\n};\n/** @internal */\nexport type TaskLeafInferred = z.infer<typeof TaskLeafSchema>;\n/** @internal */\nexport type TaskProjectInferred = z.infer<typeof TaskProjectSchema>;\n/** @internal */\nexport type TaskMilestoneInferred = z.infer<typeof TaskMilestoneSchema>;\n","/**\n * Batches style assignments; avoids repeated style recalculations.\n *\n * @param elem - The target element.\n * @param styles - A partial CSS style declaration to apply.\n */\nexport function css(elem: HTMLElement, styles: Partial<CSSStyleDeclaration>): void {\n\tfor (const [k, v] of Object.entries(styles)) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t(elem.style as any)[k] = v ?? '';\n\t}\n}\n\n/**\n * Typed element factory. Avoids littering `as HTMLElement` casts everywhere.\n *\n * @example\n * const div = el('div', {className: 'gantt-bar'});\n * const svg = el('svg', {}, 'http://www.w3.org/2000/svg');\n */\nexport function el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Partial<HTMLElementTagNameMap[K]>, ns?: never): HTMLElementTagNameMap[K];\nexport function el(tag: string, props?: Record<string, unknown>, ns?: string): Element;\nexport function el(tag: string, props?: Record<string, unknown>, ns?: string): Element {\n\tconst elem = ns ? document.createElementNS(ns, tag) : document.createElement(tag);\n\tif (props !== undefined) {\n\t\tfor (const [k, v] of Object.entries(props)) {\n\t\t\tif (k === 'style' && typeof v === 'object' && v !== null) {\n\t\t\t\tcss(elem as HTMLElement, v as Partial<CSSStyleDeclaration>);\n\t\t\t} else if (k in elem) {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t\t\t(elem as any)[k] = v;\n\t\t\t} else {\n\t\t\t\telem.setAttribute(k, String(v));\n\t\t\t}\n\t\t}\n\t}\n\treturn elem;\n}\n\n/**\n * Removes all child nodes from elem. Faster than `innerHTML = ''` for large subtrees.\n *\n * @param elem - The element to clear.\n */\nexport function clearChildren(elem: Element): void {\n\twhile (elem.firstChild !== null) {\n\t\telem.removeChild(elem.firstChild);\n\t}\n}\n\n/**\n * Appends all nodes from an array/fragment into parent in one pass.\n *\n * @param parent - The parent element.\n * @param children - The child elements or text nodes to append.\n */\nexport function appendAll(parent: Element, children: (Element | Text)[]): void {\n\tconst frag = document.createDocumentFragment();\n\tfor (const c of children) {\n\t\tfrag.appendChild(c);\n\t}\n\tparent.append(frag);\n}\n\n/**\n * Creates an SVG element in the SVG namespace.\n *\n * @param tag - The SVG tag name.\n * @param attrs - Optional attributes to set on the element.\n * @returns A new SVG element.\n */\nexport function svgEl<K extends keyof SVGElementTagNameMap>(tag: K, attrs?: Record<string, string | number>): SVGElementTagNameMap[K] {\n\tconst NS = 'http://www.w3.org/2000/svg';\n\tconst elem = document.createElementNS(NS, tag);\n\tif (attrs !== undefined) {\n\t\tfor (const [k, v] of Object.entries(attrs)) {\n\t\t\telem.setAttribute(k, String(v));\n\t\t}\n\t}\n\treturn elem;\n}\n\n/**\n * Sets multiple SVG attributes in one call.\n *\n * @param elem - The target SVG element.\n * @param attrs - Attributes to set (values are stringified).\n */\nexport function setAttrs(elem: Element, attrs: Record<string, string | number>): void {\n\tfor (const [k, v] of Object.entries(attrs)) {\n\t\telem.setAttribute(k, String(v));\n\t}\n}\n","import {el, clearChildren, appendAll} from './helpers.ts';\nimport {type GanttState, type ResolvedSpecialDay} from '../state.ts';\nimport {nextScaleBoundary, snapToScaleBoundary} from '../../timeline/scale.ts';\nimport {formatHeaderLabel, formatUpperLabel, startOfDay} from '../../domain/dateMath.ts';\n\ntype Cell = {label: string; x: number; width: number};\n\nfunction specialDayKind(\n\tdate: Date,\n\tspecialDaysByDate: Map<string, ResolvedSpecialDay>,\n\tshowWeekends: boolean,\n\tweekendDays: Set<number>,\n): 'weekend' | 'holiday' | 'custom' | null {\n\tconst dateKey = startOfDay(date).toISOString().slice(0, 10);\n\tconst specialDay = specialDaysByDate.get(dateKey);\n\tif (specialDay !== undefined) {\n\t\treturn specialDay.kind;\n\t}\n\tif (showWeekends && weekendDays.has(date.getUTCDay())) {\n\t\treturn 'weekend';\n\t}\n\treturn null;\n}\n\n/**\n * Inline style helper local to this module.\n *\n * @param elem - The target element.\n * @param styles - A partial CSS style declaration to apply.\n */\nfunction css_(elem: HTMLElement, styles: Partial<CSSStyleDeclaration>): void {\n\tfor (const [k, v] of Object.entries(styles)) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\t\t(elem.style as any)[k] = v ?? '';\n\t}\n}\n\n/**\n * Fully replaces the content of `container` with two header rows.\n * Called on scale change or viewport change only — not on scroll.\n *\n * @param container - The header container element to render into.\n * @param state - The current chart state.\n */\nexport function renderTimeHeader(container: HTMLElement, state: GanttState): void {\n\tconst {scale, viewportStart, viewportEnd, mapper, totalWidth, locale, showWeekends, weekendDays, specialDaysByDate} = state;\n\tconst weekStartsOn = locale.weekStartsOn ?? 1;\n\n\tconst upperCells: Cell[] = [];\n\tconst lowerCells: {label: string; x: number; width: number; date: Date}[] = [];\n\n\tlet cur = snapToScaleBoundary(viewportStart, scale, weekStartsOn);\n\tlet prevUpperLabel = '';\n\tlet upperStart = 0;\n\tlet upperWidth = 0;\n\n\twhile (cur < viewportEnd) {\n\t\tconst next = nextScaleBoundary(cur, scale);\n\t\tconst x = mapper.toX(cur);\n\t\tconst w = mapper.toX(next) - x;\n\t\tlowerCells.push({label: formatHeaderLabel(cur, scale, locale), x, width: w, date: new Date(cur)});\n\n\t\tconst uLabel = formatUpperLabel(cur, scale, locale);\n\t\tif (uLabel !== prevUpperLabel) {\n\t\t\tif (prevUpperLabel !== '') {\n\t\t\t\tupperCells.push({label: prevUpperLabel, x: upperStart, width: upperWidth});\n\t\t\t}\n\t\t\tprevUpperLabel = uLabel;\n\t\t\tupperStart = x;\n\t\t\tupperWidth = w;\n\t\t} else {\n\t\t\tupperWidth += w;\n\t\t}\n\t\tcur = next;\n\t}\n\tif (prevUpperLabel !== '') {\n\t\tupperCells.push({label: prevUpperLabel, x: upperStart, width: upperWidth});\n\t}\n\n\t// ── Upper row ──────────────────────────────────────────────────────────\n\tconst upperRow = el('div');\n\tcss_(upperRow, {\n\t\tposition: 'relative',\n\t\theight: '24px',\n\t\twidth: `${totalWidth}px`,\n\t\tbackground: 'var(--gantt-header-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t});\n\n\tconst upperNodes = upperCells.map((cell) => {\n\t\tconst d = el('div');\n\t\tcss_(d, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${cell.x}px`,\n\t\t\twidth: `${cell.width}px`,\n\t\t\theight: '100%',\n\t\t\tborderRight: '1px solid var(--gantt-border)',\n\t\t\tdisplay: 'flex',\n\t\t\talignItems: 'center',\n\t\t\tpaddingLeft: '8px',\n\t\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\tcolor: 'var(--gantt-text)',\n\t\t\toverflow: 'hidden',\n\t\t\twhiteSpace: 'nowrap',\n\t\t\tletterSpacing: 'var(--gantt-letter-spacing-tight)',\n\t\t\ttextTransform: 'uppercase',\n\t\t});\n\t\td.textContent = cell.label;\n\t\treturn d;\n\t});\n\n\t// ── Lower row ──────────────────────────────────────────────────────────\n\tconst lowerRow = el('div');\n\tcss_(lowerRow, {\n\t\tposition: 'relative',\n\t\theight: '28px',\n\t\twidth: `${totalWidth}px`,\n\t\tbackground: 'var(--gantt-header-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t});\n\n\tconst lowerNodes = lowerCells.map((cell) => {\n\t\tconst d = el('div');\n\t\tcss_(d, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${cell.x}px`,\n\t\t\twidth: `${cell.width}px`,\n\t\t\theight: '100%',\n\t\t\tborderRight: '1px solid var(--gantt-border)',\n\t\t\tdisplay: 'flex',\n\t\t\talignItems: 'center',\n\t\t\tjustifyContent: 'center',\n\t\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\toverflow: 'hidden',\n\t\t\twhiteSpace: 'nowrap',\n\t\t});\n\t\td.textContent = cell.label;\n\n\t\tif (scale === 'day') {\n\t\t\tconst kind = specialDayKind(cell.date, specialDaysByDate, showWeekends, weekendDays);\n\t\t\tif (kind !== null) {\n\t\t\t\td.classList.add(`gantt-header-cell--${kind}`);\n\t\t\t\tconst dateKey = startOfDay(cell.date).toISOString().slice(0, 10);\n\t\t\t\td.dataset['date'] = dateKey;\n\t\t\t\tconst specialDay = specialDaysByDate.get(dateKey);\n\t\t\t\tif (specialDay?.label !== undefined) {\n\t\t\t\t\td.dataset['label'] = specialDay.label;\n\t\t\t\t\td.title = specialDay.label;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn d;\n\t});\n\n\tappendAll(upperRow, upperNodes);\n\tappendAll(lowerRow, lowerNodes);\n\n\tclearChildren(container);\n\tcontainer.append(upperRow);\n\tcontainer.append(lowerRow);\n}\n","import {formatDisplayDate} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS} from '../../locale.ts';\nimport {type Task as GenTask} from '../../validation/schemas.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\n\n/**\n * Union of all field names that can appear on any {@link Task} variant.\n * Use when referencing task fields in grid column schemas that apply\n * across a heterogeneous set of task kinds.\n */\nexport type TaskDataField = keyof GenTask | 'endDate' | 'percentComplete' | 'open';\n\nexport type GridColumn = {\n\tid: string;\n\theader: string;\n\twidth: string;\n\talign?: 'left' | 'center' | 'right';\n\tvisible?: boolean;\n\tfield?: TaskDataField;\n\tformat?: (value: unknown, task: GenTask<Record<string, unknown>>, row: TaskNode, locale: ChartLocale) => string;\n};\n\nexport const DEFAULT_GRID_COLUMNS: GridColumn[] = [\n\t{\n\t\tid: 'name',\n\t\theader: 'Task name',\n\t\twidth: '1fr',\n\t},\n\t{\n\t\tid: 'startDate',\n\t\theader: 'Start',\n\t\twidth: '90px',\n\t\tfield: 'startDate',\n\t\tformat: (value, _task, _row, locale) => formatDisplayDate(value as string, locale),\n\t},\n\t{\n\t\tid: 'actions',\n\t\theader: '',\n\t\twidth: '28px',\n\t},\n];\n\n/**\n * Returns a localized default grid column schema.\n * Column headers use locale label overrides with `EN_US_LABELS` fallback.\n *\n * @param locale - The {@link ChartLocale} to derive column header labels from.\n * @returns An array of {@link GridColumn} objects.\n */\nexport function gridColumnDefaults(locale: ChartLocale): GridColumn[] {\n\treturn [\n\t\t{\n\t\t\tid: 'name',\n\t\t\theader: locale.labels?.columnTaskName ?? EN_US_LABELS.columnTaskName,\n\t\t\twidth: '1fr',\n\t\t},\n\t\t{\n\t\t\tid: 'startDate',\n\t\t\theader: locale.labels?.columnStartDate ?? EN_US_LABELS.columnStartDate,\n\t\t\twidth: '90px',\n\t\t\tfield: 'startDate',\n\t\t\tformat: (value, _task, _row, loc) => formatDisplayDate(String(value), loc),\n\t\t},\n\t\t{\n\t\t\tid: 'actions',\n\t\t\theader: '',\n\t\t\twidth: '28px',\n\t\t},\n\t];\n}\n\n/**\n * Builds a CSS `grid-template-columns` value from a column schema.\n *\n * @param columns - The full column schema array (only visible columns are included).\n * @returns A space-separated CSS track list.\n */\nexport function gridTemplateColumns(columns: GridColumn[]): string {\n\treturn columns\n\t\t.filter((c) => c.visible !== false)\n\t\t.map((c) => c.width)\n\t\t.join(' ');\n}\n\n/**\n * Filters a column schema to only visible columns.\n *\n * @param columns - The full column schema array.\n * @returns A new array containing only columns where `visible` is not `false`.\n */\nexport function visibleColumns(columns: GridColumn[]): GridColumn[] {\n\treturn columns.filter((c) => c.visible !== false);\n}\n\nexport const GRID_COLUMN_FR_MIN_WIDTH = 120;\n\nconst PX_RE = /^(?<value>\\d+(?:\\.\\d+)?)px$/u;\nconst FR_RE = /^(?<value>\\d+(?:\\.\\d+)?)fr$/u;\n\nfunction parseColumnMinWidth(width: string): number {\n\tconst trimmed = width.trim();\n\tconst pxMatch = PX_RE.exec(trimmed);\n\tif (pxMatch) {\n\t\treturn parseFloat(pxMatch.groups?.['value'] ?? '0');\n\t}\n\tconst frMatch = FR_RE.exec(trimmed);\n\tif (frMatch) {\n\t\treturn parseFloat(frMatch.groups?.['value'] ?? '0') * GRID_COLUMN_FR_MIN_WIDTH;\n\t}\n\treturn 0;\n}\n\n/**\n * Computes the minimum natural pixel width of a grid column schema.\n *\n * @param columns - The full column schema array.\n * @returns The sum of minimum widths: `px` columns sum directly, `fr` units contribute\n * `GRID_COLUMN_FR_MIN_WIDTH` px each.\n */\nexport function gridNaturalWidth(columns: GridColumn[]): number {\n\tlet total = 0;\n\tfor (const col of visibleColumns(columns)) {\n\t\ttotal += parseColumnMinWidth(col.width);\n\t}\n\treturn total;\n}\n","import {el, clearChildren, css} from './helpers.ts';\nimport {type GanttState} from '../state.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\nimport {type ZodTaskInferred as Task} from '../../validation/schemas.ts';\nimport {isParent} from '../../domain/tree.ts';\nimport {ROW_HEIGHT} from '../../timeline/layoutEngine.ts';\nimport {type GridColumn, gridTemplateColumns, visibleColumns} from './gridColumns.ts';\nimport {type ChartLocale, EN_US_LABELS} from '../../locale.ts';\n\nconst INDENT = 16;\nconst COLUMN_MIN_WIDTH = 30;\n\nexport type LeftPaneCallbacks = {\n\tonToggle: (id: number) => void;\n\tonTaskClick: (id: number) => void;\n\tonRowClick: (payload: {id: number; task: Task}) => void;\n\tonTaskDoubleClick: (payload: {id: number; task: Task}) => void;\n\tonTaskAdd: (id: number) => void;\n};\n\nexport function toTask(node: TaskNode): Task {\n\tconst base = {\n\t\tid: node.id,\n\t\ttext: node.text,\n\t\tstartDate: node.startDate,\n\t\t...(node.parent === undefined ? {} : {parent: node.parent}),\n\t\t...(node.color === undefined ? {} : {color: node.color}),\n\t\t...(node.data === undefined ? {} : {data: node.data}),\n\t};\n\n\tswitch (node.kind) {\n\t\tcase 'task': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'task',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t};\n\t\t}\n\t\tcase 'project': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'project',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t\topen: node.open,\n\t\t\t};\n\t\t}\n\t\tcase 'milestone': {\n\t\t\treturn {...base, kind: 'milestone'};\n\t\t}\n\t}\n}\n\nfunction getTaskField(task: Task, field: string): unknown {\n\tswitch (field) {\n\t\tcase 'endDate': {\n\t\t\treturn task.kind !== 'milestone' ? task.endDate : undefined;\n\t\t}\n\t\tcase 'percentComplete': {\n\t\t\treturn task.kind !== 'milestone' ? task.percentComplete : undefined;\n\t\t}\n\t\tcase 'open': {\n\t\t\treturn task.kind === 'project' ? task.open : undefined;\n\t\t}\n\t\tdefault: {\n\t\t\treturn (task as Record<string, unknown>)[field];\n\t\t}\n\t}\n}\n\nfunction buildTreeNameCell(row: TaskNode, expandedIds: Set<number>, cbs: LeftPaneCallbacks): HTMLElement {\n\tconst hasChildren = isParent(row);\n\tconst expanded = expandedIds.has(row.id);\n\n\tconst cell = el('div');\n\tcss(cell, {\n\t\tdisplay: 'flex',\n\t\talignItems: 'center',\n\t\tpaddingLeft: `${row.depth * INDENT}px`,\n\t\tgap: '4px',\n\t\toverflow: 'hidden',\n\t});\n\n\tif (hasChildren) {\n\t\tconst btn = el('button');\n\t\tbtn.className = 'gantt-toggle';\n\t\tbtn.textContent = expanded ? '\\u25BE' : '\\u25B8';\n\t\tcss(btn, {\n\t\t\twidth: '16px',\n\t\t\theight: '16px',\n\t\t\tdisplay: 'flex',\n\t\t\talignItems: 'center',\n\t\t\tjustifyContent: 'center',\n\t\t\tbackground: 'none',\n\t\t\tborder: 'none',\n\t\t\tcursor: 'pointer',\n\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\tpadding: '0',\n\t\t\tflexShrink: '0',\n\t\t});\n\t\tbtn.addEventListener('click', (e) => {\n\t\t\te.stopPropagation();\n\t\t\tcbs.onToggle(row.id);\n\t\t});\n\t\tcell.append(btn);\n\t} else {\n\t\tconst spacer = el('span');\n\t\tspacer.style.width = '16px';\n\t\tspacer.style.flexShrink = '0';\n\t\tcell.append(spacer);\n\t}\n\n\tconst label = el('span');\n\tcss(label, {\n\t\tfontSize: 'var(--gantt-font-size-md)',\n\t\tfontWeight: row.kind === 'project' ? 'var(--gantt-font-weight-bold)' : 'var(--gantt-font-weight-normal)',\n\t\tcolor: 'var(--gantt-text)',\n\t\toverflow: 'hidden',\n\t\ttextOverflow: 'ellipsis',\n\t\twhiteSpace: 'nowrap',\n\t});\n\tlabel.textContent = row.text;\n\tcell.append(label);\n\n\treturn cell;\n}\n\nfunction buildDataCell(row: TaskNode, column: GridColumn, locale: ChartLocale): HTMLElement {\n\tconst cell = el('span');\n\tconst styles: Partial<CSSStyleDeclaration> = {\n\t\tfontSize: 'var(--gantt-font-size-sm)',\n\t\tcolor: 'var(--gantt-text-secondary)',\n\t\tpaddingRight: '8px',\n\t\toverflow: 'hidden',\n\t\ttextOverflow: 'ellipsis',\n\t\twhiteSpace: 'nowrap',\n\t};\n\tif (column.align !== undefined) {\n\t\tstyles.textAlign = column.align;\n\t}\n\tcss(cell, styles);\n\n\tconst task = toTask(row);\n\tif (column.field !== undefined) {\n\t\tconst rawValue = getTaskField(task, column.field);\n\t\tif (column.format !== undefined) {\n\t\t\tcell.textContent = column.format(rawValue, task, row, locale);\n\t\t} else {\n\t\t\tcell.textContent =\n\t\t\t\trawValue !== null && rawValue !== undefined\n\t\t\t\t\t? typeof rawValue === 'object'\n\t\t\t\t\t\t? JSON.stringify(rawValue)\n\t\t\t\t\t\t: String(rawValue as string | number | boolean)\n\t\t\t\t\t: '';\n\t\t}\n\t}\n\n\treturn cell;\n}\n\nfunction buildAddButton(row: TaskNode, cbs: LeftPaneCallbacks, locale: ChartLocale): HTMLElement {\n\tconst btn = el('button');\n\tbtn.className = 'gantt-add-btn';\n\tbtn.textContent = '+';\n\tbtn.title = locale.labels?.addSubtaskTitle ?? EN_US_LABELS.addSubtaskTitle;\n\tcss(btn, {\n\t\tbackground: 'none',\n\t\tborder: 'none',\n\t\tcursor: 'pointer',\n\t\tcolor: 'var(--gantt-text-secondary)',\n\t\tfontSize: 'var(--gantt-font-size-lg)',\n\t\tlineHeight: '1',\n\t});\n\tbtn.addEventListener('click', (event) => {\n\t\tevent.stopPropagation();\n\t\tcbs.onTaskAdd(row.id);\n\t});\n\n\treturn btn;\n}\n\nfunction buildActionsPlaceholder(): HTMLElement {\n\tconst div = el('div');\n\treturn div;\n}\n\nfunction buildCell(\n\tcolumn: GridColumn,\n\trow: TaskNode,\n\texpandedIds: Set<number>,\n\tcbs: LeftPaneCallbacks,\n\tlocale: ChartLocale,\n\tshowAddTaskButton: boolean,\n): HTMLElement {\n\tswitch (column.id) {\n\t\tcase 'name': {\n\t\t\treturn buildTreeNameCell(row, expandedIds, cbs);\n\t\t}\n\t\tcase 'actions': {\n\t\t\treturn showAddTaskButton ? buildAddButton(row, cbs, locale) : buildActionsPlaceholder();\n\t\t}\n\t\tdefault: {\n\t\t\treturn buildDataCell(row, column, locale);\n\t\t}\n\t}\n}\n\nfunction buildRow(\n\trow: TaskNode,\n\tselectedId: number | null,\n\texpandedIds: Set<number>,\n\tcbs: LeftPaneCallbacks,\n\tcolumns: GridColumn[],\n\tlocale: ChartLocale,\n\tshowAddTaskButton: boolean,\n): HTMLElement {\n\tconst selected = row.id === selectedId;\n\n\tconst wrapper = el('div');\n\twrapper.className = 'gantt-row';\n\tcss(wrapper, {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: gridTemplateColumns(columns),\n\t\theight: `${ROW_HEIGHT}px`,\n\t\talignItems: 'center',\n\t\tpaddingLeft: '8px',\n\t\tbackground: selected ? 'var(--gantt-row-selected)' : 'var(--gantt-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t\tcursor: 'default',\n\t\tboxSizing: 'border-box',\n\t});\n\twrapper.tabIndex = 0;\n\twrapper.setAttribute('role', 'row');\n\twrapper.setAttribute('aria-selected', String(selected));\n\twrapper.dataset['taskId'] = String(row.id);\n\twrapper.addEventListener('click', () => {\n\t\tconst task = toTask(row);\n\t\tcbs.onRowClick({id: row.id, task});\n\t});\n\twrapper.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onTaskClick(row.id);\n\t\t}\n\t});\n\n\tfor (const column of visibleColumns(columns)) {\n\t\twrapper.append(buildCell(column, row, expandedIds, cbs, locale, showAddTaskButton));\n\t}\n\n\treturn wrapper;\n}\n\n/**\n * Renders the left grid pane.\n *\n * @param container - The left pane body element to render into.\n * @param state - The current chart state.\n * @param cbs - The left pane callbacks.\n * @param columns - The grid column schema.\n * @param showAddTaskButton - Whether to render the add-subtask button in the actions column.\n */\nexport function renderLeftPane(container: HTMLElement, state: GanttState, cbs: LeftPaneCallbacks, columns: GridColumn[], showAddTaskButton = true): void {\n\tconst {allRows, selectedId, expandedIds, startIndex, endIndex, paddingTop, paddingBottom, locale} = state;\n\n\tconst frag = document.createDocumentFragment();\n\n\tif (paddingTop > 0) {\n\t\tconst spacer = el('div');\n\t\tspacer.style.height = `${paddingTop}px`;\n\t\tfrag.append(spacer);\n\t}\n\n\tfor (const row of allRows.slice(startIndex, endIndex + 1)) {\n\t\tfrag.append(buildRow(row, selectedId, expandedIds, cbs, columns, locale, showAddTaskButton));\n\t}\n\n\tif (paddingBottom > 0) {\n\t\tconst spacer = el('div');\n\t\tspacer.style.height = `${paddingBottom}px`;\n\t\tfrag.append(spacer);\n\t}\n\n\tclearChildren(container);\n\tcontainer.append(frag);\n}\n\n/**\n * Builds the header row for the left pane.\n *\n * @param columns - The grid column schema.\n * @param locale - The current chart locale.\n * @returns The header DOM element.\n */\nexport function buildLeftPaneHeader(columns: GridColumn[], locale: ChartLocale): HTMLElement {\n\tconst header = el('div');\n\tcss(header, {\n\t\tdisplay: 'grid',\n\t\tgridTemplateColumns: gridTemplateColumns(columns),\n\t\theight: '52px',\n\t\tbackground: 'var(--gantt-header-bg)',\n\t\tborderBottom: '1px solid var(--gantt-border)',\n\t\tpaddingLeft: '8px',\n\t\talignItems: 'flex-end',\n\t\tpaddingBottom: '4px',\n\t\tboxSizing: 'border-box',\n\t});\n\n\tconst visible = visibleColumns(columns);\n\tfor (let i = 0; i < visible.length; i++) {\n\t\tconst column = visible[i];\n\t\tif (column === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst wrapper = el('div');\n\t\tcss(wrapper, {position: 'relative', display: 'flex', alignItems: 'flex-end'});\n\n\t\tif (i === 0 && visible[0]?.id === 'name') {\n\t\t\tconst btnContainer = el('div');\n\t\t\tbtnContainer.className = 'gantt-header-tree-controls';\n\t\t\tcss(btnContainer, {\n\t\t\t\tdisplay: 'flex',\n\t\t\t\tgap: '4px',\n\t\t\t\tmarginRight: '6px',\n\t\t\t\tpaddingBottom: '1px',\n\t\t\t});\n\n\t\t\tconst expandBtn = el('button');\n\t\t\texpandBtn.className = 'gantt-header-expand-btn';\n\t\t\texpandBtn.textContent = '+';\n\t\t\texpandBtn.title = locale.labels?.expandAllTitle ?? EN_US_LABELS.expandAllTitle;\n\t\t\texpandBtn.setAttribute('aria-label', expandBtn.title);\n\t\t\tcss(expandBtn, {\n\t\t\t\twidth: '18px',\n\t\t\t\theight: '18px',\n\t\t\t\tdisplay: 'flex',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\tbackground: 'var(--gantt-header-bg)',\n\t\t\t\tborder: '1px solid var(--gantt-border)',\n\t\t\t\tborderRadius: '3px',\n\t\t\t\tcursor: 'pointer',\n\t\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\t\tfontSize: '14px',\n\t\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\t\tlineHeight: '1',\n\t\t\t\tpadding: '0',\n\t\t\t});\n\n\t\t\tconst collapseBtn = el('button');\n\t\t\tcollapseBtn.className = 'gantt-header-collapse-btn';\n\t\t\tcollapseBtn.textContent = '\\u2212';\n\t\t\tcollapseBtn.title = locale.labels?.collapseAllTitle ?? EN_US_LABELS.collapseAllTitle;\n\t\t\tcollapseBtn.setAttribute('aria-label', collapseBtn.title);\n\t\t\tcss(collapseBtn, {\n\t\t\t\twidth: '18px',\n\t\t\t\theight: '18px',\n\t\t\t\tdisplay: 'flex',\n\t\t\t\talignItems: 'center',\n\t\t\t\tjustifyContent: 'center',\n\t\t\t\tbackground: 'var(--gantt-header-bg)',\n\t\t\t\tborder: '1px solid var(--gantt-border)',\n\t\t\t\tborderRadius: '3px',\n\t\t\t\tcursor: 'pointer',\n\t\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\t\tfontSize: '14px',\n\t\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\t\tlineHeight: '1',\n\t\t\t\tpadding: '0',\n\t\t\t});\n\n\t\t\tbtnContainer.append(expandBtn, collapseBtn);\n\t\t\twrapper.append(btnContainer);\n\t\t}\n\n\t\tconst cell = el('span');\n\t\tcss(cell, {\n\t\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\t\tfontWeight: 'var(--gantt-font-weight-bold)',\n\t\t\tcolor: 'var(--gantt-text-secondary)',\n\t\t\tletterSpacing: 'var(--gantt-letter-spacing-wide)',\n\t\t\ttextTransform: 'uppercase',\n\t\t\tpaddingRight: '8px',\n\t\t});\n\t\tif (column.align !== undefined) {\n\t\t\tcell.style.textAlign = column.align;\n\t\t}\n\t\tcell.textContent = column.header;\n\t\twrapper.append(cell);\n\n\t\tif (i < visible.length - 1) {\n\t\t\tconst handle = el('div');\n\t\t\thandle.className = 'gantt-col-resize-handle';\n\t\t\tcss(handle, {\n\t\t\t\tposition: 'absolute',\n\t\t\t\tright: '-3px',\n\t\t\t\ttop: '0',\n\t\t\t\tbottom: '0',\n\t\t\t\twidth: '6px',\n\t\t\t\tcursor: 'col-resize',\n\t\t\t\tzIndex: '1',\n\t\t\t});\n\t\t\twrapper.append(handle);\n\t\t}\n\n\t\theader.append(wrapper);\n\t}\n\n\treturn header;\n}\n\nexport const COLUMN_RESIZE_MIN_WIDTH = COLUMN_MIN_WIDTH;\n\n/**\n * Wires up column resize interactions on header handles.\n * Must be called after the header is in the DOM (so `getBoundingClientRect` works).\n *\n * @param headerEl - The header element containing resize handles.\n * @param bodyEl - The body element whose rows share the column widths.\n * @param columns - The grid column schema (mutated in place on resize end).\n * @param onChange - Optional callback fired on drag end with updated columns.\n * @returns A cleanup function that removes all resize listeners.\n */\nexport function setupColumnResize(headerEl: HTMLElement, bodyEl: HTMLElement, columns: GridColumn[], onChange?: (columns: GridColumn[]) => void): () => void {\n\tconst handles = headerEl.querySelectorAll<HTMLElement>('.gantt-col-resize-handle');\n\tconst cleanups: (() => void)[] = [];\n\n\tfor (let colIndex = 0; colIndex < handles.length; colIndex++) {\n\t\tconst handle = handles.item(colIndex);\n\t\tif (handle === null) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst capturedColIndex = colIndex;\n\n\t\tconst onPointerDown = (e: PointerEvent): void => {\n\t\t\tif (e.button !== 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\n\t\t\tconst startX = e.clientX;\n\t\t\tconst cells = [...headerEl.children] as HTMLElement[];\n\t\t\tconst startWidths = cells.map((c) => c.getBoundingClientRect().width);\n\n\t\t\tconst onMove = (me: PointerEvent): void => {\n\t\t\t\tconst dx = me.clientX - startX;\n\t\t\t\tconst newWidths = [...startWidths];\n\n\t\t\t\tnewWidths[capturedColIndex] = Math.max(COLUMN_MIN_WIDTH, (startWidths[capturedColIndex] ?? 0) + dx);\n\n\t\t\t\tif (capturedColIndex + 1 < newWidths.length) {\n\t\t\t\t\tnewWidths[capturedColIndex + 1] = Math.max(COLUMN_MIN_WIDTH, (startWidths[capturedColIndex + 1] ?? 0) - dx);\n\t\t\t\t}\n\n\t\t\t\tconst template = newWidths.map((w) => `${Math.round(w)}px`).join(' ');\n\t\t\t\theaderEl.style.gridTemplateColumns = template;\n\n\t\t\t\tconst rows = bodyEl.querySelectorAll<HTMLElement>('[role=\"row\"]');\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\trow.style.gridTemplateColumns = template;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst onUp = (): void => {\n\t\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\t\twindow.removeEventListener('pointerup', onUp);\n\n\t\t\t\tconst finalCells = [...headerEl.children] as HTMLElement[];\n\t\t\t\tconst visible = visibleColumns(columns);\n\t\t\t\tfor (let i = 0; i < visible.length && i < finalCells.length; i++) {\n\t\t\t\t\tconst col = visible[i];\n\t\t\t\t\tconst cell = finalCells[i];\n\t\t\t\t\tif (col !== undefined && cell !== undefined) {\n\t\t\t\t\t\tconst w = cell.getBoundingClientRect().width;\n\t\t\t\t\t\tcol.width = `${Math.round(w)}px`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tonChange?.([...columns]);\n\t\t\t};\n\n\t\t\twindow.addEventListener('pointermove', onMove);\n\t\t\twindow.addEventListener('pointerup', onUp);\n\t\t};\n\n\t\thandle.addEventListener('pointerdown', onPointerDown);\n\t\tcleanups.push(() => {\n\t\t\thandle.removeEventListener('pointerdown', onPointerDown);\n\t\t});\n\t}\n\n\treturn () => {\n\t\tfor (const cleanup of cleanups) {\n\t\t\tcleanup();\n\t\t}\n\t};\n}\n","import {setAttrs} from './helpers.ts';\nimport {type RoutedLink} from '../../rendering/linkRouter.ts';\n\nconst NS = 'http://www.w3.org/2000/svg';\nconst ARROW_PATH = 'M 0 1 L 10 5 L 0 9 Z';\nconst ARROW_SIZE = 6;\n\ntype DependencyCallbacks = {\n\tonLinkClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonLinkDblClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n};\n\n/**\n * Creates the SVG overlay element. Call once; pass to updateDependencyLayer on each render.\n * Also creates a hidden ghost-line path used during link-creation drags.\n *\n * The SVG is initially zero-sized; `updateDependencyLayer` sets width/height each frame.\n *\n * @param _totalWidth - The total pixel width of the SVG viewport.\n * @param _totalHeight - The total pixel height of the SVG viewport.\n * @returns An `SVGSVGElement` ready to be inserted into the DOM.\n */\nexport function createDependencyLayer(_totalWidth: number, _totalHeight: number): SVGSVGElement {\n\tconst svg = document.createElementNS(NS, 'svg');\n\tObject.assign(svg.style, {\n\t\tposition: 'absolute',\n\t\ttop: '0',\n\t\tleft: '0',\n\t\tpointerEvents: 'none',\n\t\toverflow: 'visible',\n\t\tzIndex: '1',\n\t});\n\n\t// Arrow markers (created once, reused by all paths via xlink/href)\n\tconst defs = document.createElementNS(NS, 'defs');\n\n\tfor (const [id, color] of [\n\t\t['gantt-arrow', 'var(--gantt-link)'],\n\t\t['gantt-arrow-hi', 'var(--gantt-link-hi)'],\n\t] as const) {\n\t\tconst marker = document.createElementNS(NS, 'marker');\n\t\tsetAttrs(marker, {\n\t\t\tid,\n\t\t\tviewBox: '0 0 10 10',\n\t\t\trefX: '10',\n\t\t\trefY: '5',\n\t\t\tmarkerWidth: ARROW_SIZE,\n\t\t\tmarkerHeight: ARROW_SIZE,\n\t\t\torient: 'auto',\n\t\t});\n\t\tconst path = document.createElementNS(NS, 'path');\n\t\tsetAttrs(path, {d: ARROW_PATH, fill: color});\n\t\tmarker.append(path);\n\t\tdefs.append(marker);\n\t}\n\n\tsvg.append(defs);\n\n\t// Ghost line for link-creation drag (hidden by default)\n\tconst ghostPath = document.createElementNS(NS, 'path');\n\tsetAttrs(ghostPath, {\n\t\td: '',\n\t\tfill: 'none',\n\t\tstroke: 'var(--gantt-link)',\n\t\t'stroke-width': '1.5',\n\t\t'stroke-dasharray': '5 3',\n\t});\n\tghostPath.classList.add('gantt-ghost-line');\n\tghostPath.style.display = 'none';\n\tsvg.append(ghostPath);\n\n\treturn svg;\n}\n\n/**\n * Shows or updates the ghost line drawn during a link-creation drag.\n *\n * @param svg - The SVG dependency layer element.\n * @param x1 - Start X coordinate.\n * @param y1 - Start Y coordinate.\n * @param x2 - End X coordinate.\n * @param y2 - End Y coordinate.\n * @param valid - When `true`, the line is drawn solid with an arrow marker.\n */\nexport function showGhostLine(svg: SVGSVGElement, x1: number, y1: number, x2: number, y2: number, valid: boolean): void {\n\tconst ghost = svg.querySelector<SVGPathElement>('path.gantt-ghost-line');\n\tif (ghost === null) {\n\t\treturn;\n\t}\n\tsetAttrs(ghost, {\n\t\td: `M ${x1},${y1} L ${x2},${y2}`,\n\t});\n\tif (valid) {\n\t\tghost.removeAttribute('stroke-dasharray');\n\t} else {\n\t\tghost.setAttribute('stroke-dasharray', '5 3');\n\t}\n\tif (valid) {\n\t\tghost.setAttribute('marker-end', 'url(#gantt-arrow)');\n\t} else {\n\t\tghost.removeAttribute('marker-end');\n\t}\n\tghost.style.display = '';\n}\n\n/**\n * Hides the ghost line after a link-creation drag completes or is cancelled.\n *\n * @param svg - The SVG dependency layer element.\n */\nexport function hideGhostLine(svg: SVGSVGElement): void {\n\tconst ghost = svg.querySelector<SVGPathElement>('path.gantt-ghost-line');\n\tif (ghost !== null) {\n\t\tghost.style.display = 'none';\n\t\tghost.removeAttribute('marker-end');\n\t}\n}\n\n/**\n * Replaces all path elements in the SVG to reflect the current link set.\n * The `<defs>` node (first child) is preserved.\n *\n * @param svg - The SVG dependency layer element.\n * @param links - The array of routed links to render.\n * @param totalWidth - The total pixel width of the SVG viewport.\n * @param totalHeight - The total pixel height of the SVG viewport.\n * @param selectedTaskId - The currently selected task ID, or `null`.\n * @param highlightLinkedDependenciesOnSelect - When `true`, links connected to the selected task use highlight styling.\n * @param cbs - Optional callbacks for link click and double-click events.\n */\nexport function updateDependencyLayer(\n\tsvg: SVGSVGElement,\n\tlinks: RoutedLink[],\n\ttotalWidth: number,\n\ttotalHeight: number,\n\tselectedTaskId: number | null,\n\thighlightLinkedDependenciesOnSelect: boolean,\n\tcbs?: DependencyCallbacks,\n): void {\n\tsetAttrs(svg, {width: totalWidth, height: totalHeight});\n\n\tconst toRemove = [...svg.children].slice(1).filter((c) => !c.classList.contains('gantt-ghost-line'));\n\tfor (const node of toRemove) {\n\t\tsvg.removeChild(node);\n\t}\n\n\tconst ghost = svg.querySelector<SVGPathElement>('path.gantt-ghost-line');\n\n\tfor (const link of links) {\n\t\tconst {points} = link;\n\t\tif (points.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [first, ...rest] = points as [(typeof points)[0], ...(typeof points)[0][]];\n\t\tconst d = `M ${first.x},${first.y}${rest.map((p) => ` L ${p.x},${p.y}`).join('')}`;\n\n\t\tconst isRelated =\n\t\t\thighlightLinkedDependenciesOnSelect && selectedTaskId !== null && (link.sourceTaskId === selectedTaskId || link.targetTaskId === selectedTaskId);\n\n\t\tconst path = document.createElementNS(NS, 'path');\n\t\tsetAttrs(path, {\n\t\t\td,\n\t\t\tfill: 'none',\n\t\t\tstroke: isRelated ? 'var(--gantt-link-hi)' : 'var(--gantt-link)',\n\t\t\t'stroke-width': isRelated ? '1.8' : '1.5',\n\t\t\t'stroke-linejoin': 'round',\n\t\t\t'marker-end': isRelated ? 'url(#gantt-arrow-hi)' : 'url(#gantt-arrow)',\n\t\t\t'data-link-id': String(link.linkId),\n\t\t});\n\t\tpath.style.pointerEvents = 'visibleStroke';\n\t\tpath.style.cursor = 'pointer';\n\n\t\tpath.addEventListener('click', (event) => {\n\t\t\tif (event.detail === 1) {\n\t\t\t\tcbs?.onLinkClick?.({\n\t\t\t\t\tid: link.linkId,\n\t\t\t\t\tsource: link.sourceTaskId,\n\t\t\t\t\ttarget: link.targetTaskId,\n\t\t\t\t\ttype: link.type,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tpath.addEventListener('dblclick', (_event) => {\n\t\t\tcbs?.onLinkDblClick?.({\n\t\t\t\tid: link.linkId,\n\t\t\t\tsource: link.sourceTaskId,\n\t\t\t\ttarget: link.targetTaskId,\n\t\t\t\ttype: link.type,\n\t\t\t});\n\t\t});\n\n\t\tif (ghost !== null) {\n\t\t\tsvg.insertBefore(path, ghost);\n\t\t} else {\n\t\t\tsvg.append(path);\n\t\t}\n\t}\n}\n","import {type TaskNode} from '../../domain/tree.ts';\nimport {type PixelMapper} from '../../timeline/pixelMapper.ts';\nimport {parseDate, addDays} from '../../domain/dateMath.ts';\nimport {type ZodTaskInferred as Task} from '../../validation/schemas.ts';\n\ntype InternalCallbacks = {\n\tonTaskClick?: (id: number) => void;\n\tonTaskMove?: (payload: {id: number; startDate: Date}) => void;\n\tonTaskResize?: (payload: {id: number; endDate: string}) => void;\n\tonTaskDoubleClick?: (payload: {id: number; task: Task}) => void;\n\t_onTaskMoveFinal?: (payload: {id: number; startDate: Date}) => Promise<boolean>;\n\t_onTaskResizeFinal?: (payload: {id: number; endDate: string}) => Promise<boolean>;\n\tonTaskProgressDrag?: (payload: {id: number; percentComplete: number}) => void;\n\t_onTaskProgressDragFinal?: (payload: {id: number; percentComplete: number}) => Promise<boolean>;\n};\n\nexport function toTask(node: TaskNode): Task {\n\tconst base = {\n\t\tid: node.id,\n\t\ttext: node.text,\n\t\tstartDate: node.startDate,\n\t\t...(node.parent === undefined ? {} : {parent: node.parent}),\n\t\t...(node.color === undefined ? {} : {color: node.color}),\n\t\t...(node.readonly === undefined ? {} : {readonly: node.readonly}),\n\t\t...(node.data === undefined ? {} : {data: node.data}),\n\t};\n\n\tswitch (node.kind) {\n\t\tcase 'task': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'task',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t};\n\t\t}\n\t\tcase 'project': {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tkind: 'project',\n\t\t\t\tendDate: node.endDate,\n\t\t\t\tpercentComplete: node.percentComplete,\n\t\t\t\topen: node.open,\n\t\t\t};\n\t\t}\n\t\tcase 'milestone': {\n\t\t\treturn {...base, kind: 'milestone'};\n\t\t}\n\t}\n}\n\n/**\n * Attaches drag-to-move and resize listeners to a bar element.\n *\n * Design: all mutable state lives in closure variables captured at mousedown.\n * No global state; multiple bars can be dragged independently (one at a time).\n *\n * @param barEl - The bar DOM element.\n * @param resizeHandleEl - The resize handle DOM element.\n * @param task - The {@link TaskNode} for this bar.\n * @param getMapper - A function returning the current {@link PixelMapper} (snapshotted at mousedown).\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachDrag(barEl: HTMLElement, resizeHandleEl: HTMLElement, task: TaskNode, getMapper: () => PixelMapper, cbs: InternalCallbacks): () => void {\n\tfunction onBarDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\ttry {\n\t\t\tbarEl.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\t\tcbs.onTaskClick?.(task.id);\n\n\t\tconst startX = e.clientX;\n\t\tconst originDate = parseDate(task.startDate);\n\t\tconst mapper = getMapper();\n\n\t\tlet lastDays = 0;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tlastDays = Math.round(mapper.widthToDurationDays(dx));\n\t\t\tcbs.onTaskMove?.({id: task.id, startDate: addDays(originDate, lastDays)});\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tbarEl.style.cursor = 'grab';\n\t\t\tif (lastDays !== 0) {\n\t\t\t\tvoid cbs._onTaskMoveFinal?.({id: task.id, startDate: addDays(originDate, lastDays)});\n\t\t\t}\n\t\t}\n\n\t\tbarEl.style.cursor = 'grabbing';\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tfunction onResizeDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\ttry {\n\t\t\tresizeHandleEl.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\n\t\tconst startX = e.clientX;\n\t\tif (task.kind === 'milestone') {\n\t\t\treturn;\n\t\t}\n\t\tconst origEnd = parseDate(task.endDate);\n\t\tconst mapper = getMapper();\n\n\t\tlet lastEnd = origEnd;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst daysDelta = Math.round(mapper.widthToDurationDays(dx));\n\t\t\tlastEnd = addDays(origEnd, daysDelta);\n\t\t\tcbs.onTaskResize?.({id: task.id, endDate: lastEnd.toISOString().slice(0, 10)});\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tvoid cbs._onTaskResizeFinal?.({id: task.id, endDate: lastEnd.toISOString().slice(0, 10)});\n\t\t}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tbarEl.addEventListener('pointerdown', onBarDown);\n\tresizeHandleEl.addEventListener('pointerdown', onResizeDown);\n\n\treturn () => {\n\t\tbarEl.removeEventListener('pointerdown', onBarDown);\n\t\tresizeHandleEl.removeEventListener('pointerdown', onResizeDown);\n\t};\n}\n\n/**\n * Attaches drag-to-change-progress listeners to a progress overlay element.\n *\n * @param progressEl - The progress overlay DOM element.\n * @param barEl - The bar DOM element (for width measurement).\n * @param task - The {@link TaskNode} for this bar.\n * @param _getMapper - A function returning the current {@link PixelMapper} (unused, kept for API symmetry).\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachProgressDrag(\n\tprogressEl: HTMLElement,\n\tbarEl: HTMLElement,\n\ttask: TaskNode,\n\t_getMapper: () => PixelMapper,\n\tcbs: InternalCallbacks,\n): () => void {\n\tfunction onProgressDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tcbs.onTaskClick?.(task.id);\n\t\ttry {\n\t\t\tprogressEl.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\n\t\tconst startX = e.clientX;\n\t\tconst barWidth = barEl.getBoundingClientRect().width;\n\t\tconst origPercent = task.kind !== 'milestone' ? (task.percentComplete ?? 0) : 0;\n\n\t\tlet lastPercent = origPercent;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst percentDelta = barWidth > 0 ? (dx / barWidth) * 100 : 0;\n\t\t\tlastPercent = Math.max(0, Math.min(100, Math.round(origPercent + percentDelta)));\n\t\t\tcbs.onTaskProgressDrag?.({id: task.id, percentComplete: lastPercent});\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tprogressEl.style.cursor = 'ew-resize';\n\t\t\tvoid cbs._onTaskProgressDragFinal?.({id: task.id, percentComplete: lastPercent});\n\t\t}\n\n\t\tprogressEl.style.cursor = 'ew-resize';\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tprogressEl.addEventListener('pointerdown', onProgressDown);\n\n\treturn () => {\n\t\tprogressEl.removeEventListener('pointerdown', onProgressDown);\n\t};\n}\n\n/**\n * Attaches click-to-select on a milestone diamond.\n *\n * @param diamondEl - The milestone diamond DOM element.\n * @param taskId - The task ID to select.\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachMilestoneClick(diamondEl: HTMLElement, taskId: number, cbs: InternalCallbacks): () => void {\n\tfunction onClick(): void {\n\t\tcbs.onTaskClick?.(taskId);\n\t}\n\tfunction onDoubleClick(event: MouseEvent): void {\n\t\tif (event.detail === 2) {\n\t\t\tconst task = (diamondEl as HTMLElement & {__task?: Task}).__task;\n\t\t\tif (task === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcbs.onTaskDoubleClick?.({id: taskId, task});\n\t\t}\n\t}\n\tdiamondEl.addEventListener('click', onClick);\n\tdiamondEl.addEventListener('click', onDoubleClick);\n\treturn () => {\n\t\tdiamondEl.removeEventListener('click', onClick);\n\t\tdiamondEl.removeEventListener('click', onDoubleClick);\n\t};\n}\n\nexport function bindMilestoneTask(diamondEl: HTMLElement, task: Task): void {\n\t(diamondEl as HTMLElement & {__task?: Task}).__task = task;\n}\n","import {showGhostLine, hideGhostLine} from '../dom/dependencyLayer.ts';\n\ntype LinkCreationCallbacks = {\n\tonLinkCreate?: (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n};\n\n/**\n * Attaches a link-creation drag listener to an endpoint handle.\n *\n * @param handle - The endpoint DOM element.\n * @param sourceTaskId - The task ID from which the link originates.\n * @param anchorX - The X anchor coordinate (task center).\n * @param anchorY - The Y anchor coordinate (task center).\n * @param svgLayer - The SVG dependency layer element for ghost line rendering.\n * @param absoluteLayer - The absolute-positioned layer for coordinate calculations.\n * @param cbs - The chart callbacks.\n * @returns A cleanup function that removes all listeners.\n */\nexport function attachLinkEndpointHandle(\n\thandle: HTMLElement,\n\tsourceTaskId: number,\n\tanchorX: number,\n\tanchorY: number,\n\tsvgLayer: SVGSVGElement,\n\tabsoluteLayer: HTMLElement,\n\tcbs: LinkCreationCallbacks,\n): () => void {\n\tfunction onPointerDown(e: PointerEvent): void {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\ttry {\n\t\t\thandle.setPointerCapture(e.pointerId);\n\t\t} catch {\n\t\t\t// Browsers/tests may reject synthetic pointer ids.\n\t\t}\n\n\t\tlet validTargetId: number | null = null;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst layerRect = absoluteLayer.getBoundingClientRect();\n\t\t\tconst x = me.clientX - layerRect.left;\n\t\t\tconst y = me.clientY - layerRect.top;\n\n\t\t\t// Hit-test for bars and milestones\n\t\t\tconst el = document.elementFromPoint(me.clientX, me.clientY);\n\t\t\tconst barEl = el?.closest<HTMLElement>('[data-task-id]');\n\t\t\tconst targetId = barEl !== null && barEl !== undefined ? Number(barEl.dataset['taskId']) : null;\n\n\t\t\tvalidTargetId = targetId !== null && targetId !== sourceTaskId ? targetId : null;\n\n\t\t\tshowGhostLine(svgLayer, anchorX, anchorY, x, y, validTargetId !== null);\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\thideGhostLine(svgLayer);\n\n\t\t\tif (validTargetId !== null) {\n\t\t\t\tcbs.onLinkCreate?.({sourceTaskId, targetTaskId: validTargetId, type: 'FS'});\n\t\t\t}\n\t\t}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\thandle.addEventListener('pointerdown', onPointerDown);\n\thandle.tabIndex = 0;\n\thandle.setAttribute('role', 'button');\n\thandle.setAttribute('aria-label', `Create link from task ${sourceTaskId}`);\n\n\tfunction onKeyDown(event: KeyboardEvent): void {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\thandle.addEventListener('keydown', onKeyDown);\n\n\treturn () => {\n\t\thandle.removeEventListener('pointerdown', onPointerDown);\n\t\thandle.removeEventListener('keydown', onKeyDown);\n\t};\n}\n\n/**\n * Creates an endpoint handle DOM element.\n * The caller must position it with inline styles and append it to the layer.\n *\n * @returns A new `HTMLElement` with the `gantt-link-endpoint` class.\n */\nexport function createEndpointHandle(): HTMLElement {\n\tconst handle = document.createElement('div');\n\thandle.className = 'gantt-link-endpoint';\n\thandle.style.position = 'absolute';\n\thandle.style.width = '10px';\n\thandle.style.height = '10px';\n\thandle.style.borderRadius = '50%';\n\thandle.style.background = 'var(--gantt-link)';\n\thandle.style.border = '2px solid var(--gantt-bg)';\n\thandle.style.cursor = 'crosshair';\n\thandle.style.zIndex = '4';\n\thandle.style.opacity = '0';\n\thandle.style.transition = 'opacity 0.15s ease, transform 0.1s ease';\n\thandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\thandle.style.pointerEvents = 'auto';\n\thandle.style.touchAction = 'none';\n\treturn handle;\n}\n","import {el, css, clearChildren} from './helpers.ts';\nimport {createDependencyLayer, updateDependencyLayer, hideGhostLine} from './dependencyLayer.ts';\nimport {attachDrag, attachMilestoneClick, bindMilestoneTask, attachProgressDrag, toTask} from '../interaction/drag.ts';\nimport {attachLinkEndpointHandle, createEndpointHandle} from '../interaction/linkCreation.ts';\nimport {type GanttState} from '../state.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\nimport {type BarLayout} from '../../timeline/layoutEngine.ts';\nimport {ROW_HEIGHT, MILESTONE_HALF, totalContentHeight} from '../../timeline/layoutEngine.ts';\nimport {nextScaleBoundary, snapToScaleBoundary} from '../../timeline/scale.ts';\nimport {startOfDay} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS, formatLabel} from '../../locale.ts';\nimport {type ZodTaskInferred as Task} from '../../validation/schemas.ts';\n\ntype RightPaneCallbacks = {\n\tonTaskClick?: (id: number) => void;\n\tonTaskMove?: (payload: {id: number; startDate: Date}) => void;\n\tonTaskResize?: (payload: {id: number; endDate: string}) => void;\n\tonTaskEditIntent?: (payload: {id: number; source: 'grid' | 'bar' | 'milestone'; trigger: 'doubleClick'; task: Task}) => void;\n\tonTaskDoubleClick?: (payload: {id: number; task: Task}) => void;\n\tonLinkCreate?: (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n\tonLinkClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonLinkDblClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\t_onTaskMoveFinal?: (payload: {id: number; startDate: Date}) => Promise<boolean>;\n\t_onTaskResizeFinal?: (payload: {id: number; endDate: string}) => Promise<boolean>;\n\tonTaskProgressDrag?: (payload: {id: number; percentComplete: number}) => void;\n\t_onTaskProgressDragFinal?: (payload: {id: number; percentComplete: number}) => Promise<boolean>;\n\tonTooltipText?: (payload: {id: number; task: Task}) => string | null;\n};\n\nconst BAR_COLOR: Record<string, string> = {\n\ttask: 'var(--gantt-task)',\n\tproject: 'var(--gantt-project)',\n\tmilestone: 'var(--gantt-milestone)',\n};\n\n/**\n * Persistent DOM references for the right pane.\n * Created once in mount.ts; updated cheaply on each render.\n */\nexport type RightPaneRefs = {\n\tscrollContainer: HTMLElement;\n\tstripeContainer: HTMLElement;\n\tabsoluteLayer: HTMLElement;\n\tsvgLayer: SVGSVGElement;\n\ttooltipEl: HTMLElement;\n\t/** Map of taskId → {bar, resizeHandle, cleanupDrag} for update-in-place */\n\tbarRegistry: Map<\n\t\tnumber,\n\t\t{\n\t\t\tbar: HTMLElement;\n\t\t\tresizeHandle: HTMLElement;\n\t\t\tcleanupDrag?: () => void;\n\t\t\tcleanupLinkHandles?: () => void;\n\t\t\tcleanupProgressDrag?: () => void;\n\t\t\tcleanupTooltip?: () => void;\n\t\t}\n\t>;\n};\n\n/**\n * Creates the skeleton DOM structure for the right pane. Call once.\n *\n * @returns A new {@link RightPaneRefs} with empty containers and bar registry.\n */\nexport function createRightPaneRefs(): RightPaneRefs {\n\tconst scrollContainer = el('div');\n\tconst stripeContainer = el('div');\n\tconst absoluteLayer = el('div');\n\tconst svgLayer = createDependencyLayer(0, 0);\n\n\tcss(stripeContainer, {position: 'relative'});\n\tcss(absoluteLayer, {position: 'absolute', top: '52px', left: '0'});\n\n\tscrollContainer.append(stripeContainer);\n\tscrollContainer.append(absoluteLayer);\n\tabsoluteLayer.append(svgLayer);\n\n\tconst tooltipEl = el('div');\n\ttooltipEl.className = 'gantt-tooltip';\n\ttooltipEl.style.display = 'none';\n\tscrollContainer.append(tooltipEl);\n\n\treturn {\n\t\tscrollContainer,\n\t\tstripeContainer,\n\t\tabsoluteLayer,\n\t\tsvgLayer,\n\t\ttooltipEl,\n\t\tbarRegistry: new Map(),\n\t};\n}\n\nfunction ariaLabel(locale: ChartLocale, key: 'ariaTask' | 'ariaMilestone', arg: string): string {\n\tconst template = locale.labels?.[key] ?? EN_US_LABELS[key];\n\treturn formatLabel(template, arg);\n}\n\nfunction renderSpecialDayBackgrounds(layer: HTMLElement, beforeNode: Element, state: GanttState, contentHeight: number): void {\n\tconst {mapper, viewportStart, viewportEnd, showWeekends, weekendDays, specialDaysByDate} = state;\n\tlet cur = startOfDay(viewportStart);\n\n\twhile (cur < viewportEnd) {\n\t\tconst next = new Date(cur.getTime() + 86_400_000);\n\t\tconst x = mapper.toX(cur);\n\t\tconst width = Math.max(1, mapper.toX(next) - x);\n\t\tconst dateKey = cur.toISOString().slice(0, 10);\n\t\tconst specialDay = specialDaysByDate.get(dateKey);\n\t\tconst isWeekend = weekendDays.has(cur.getUTCDay());\n\n\t\tlet kind: 'weekend' | 'holiday' | 'custom' | null = null;\n\t\tif (specialDay !== undefined) {\n\t\t\tconst {kind: specialKind} = specialDay;\n\t\t\tkind = specialKind;\n\t\t} else if (showWeekends && isWeekend) {\n\t\t\tkind = 'weekend';\n\t\t}\n\n\t\tif (kind !== null) {\n\t\t\tconst dayCell = el('div');\n\t\t\tdayCell.className = `gantt-day-cell gantt-day-cell--${kind}`;\n\t\t\tif (specialDay?.className !== undefined) {\n\t\t\t\tdayCell.classList.add(specialDay.className);\n\t\t\t}\n\t\t\tdayCell.dataset['date'] = dateKey;\n\t\t\tif (specialDay?.label !== undefined) {\n\t\t\t\tdayCell.dataset['label'] = specialDay.label;\n\t\t\t\tdayCell.title = specialDay.label;\n\t\t\t}\n\t\t\tcss(dayCell, {\n\t\t\t\tposition: 'absolute',\n\t\t\t\tleft: `${x}px`,\n\t\t\t\ttop: '0',\n\t\t\t\twidth: `${width}px`,\n\t\t\t\theight: `${contentHeight}px`,\n\t\t\t\tpointerEvents: 'none',\n\t\t\t\tzIndex: '1',\n\t\t\t});\n\t\t\tlayer.insertBefore(dayCell, beforeNode);\n\t\t}\n\n\t\tcur = next;\n\t}\n}\n\n// ─── Bar ─────────────────────────────────────────────────────────────────────\n\nfunction renderBar(\n\tlayer: HTMLElement,\n\tsvgLayer: SVGSVGElement,\n\ttask: TaskNode,\n\tlayout: BarLayout,\n\tselectedId: number | null,\n\tregistry: RightPaneRefs['barRegistry'],\n\tstate: GanttState,\n\tcbs: RightPaneCallbacks,\n\ttooltipEl: HTMLElement,\n): void {\n\tconst selected = task.id === selectedId;\n\tconst readonly = task.readonly === true;\n\tconst color = BAR_COLOR[layout.kind] ?? BAR_COLOR['task'];\n\n\tconst bar = el('div');\n\tbar.className = `gantt-bar${selected ? ' gantt-bar--selected gantt-shape--selected' : ''}`;\n\tcss(bar, {\n\t\tposition: 'absolute',\n\t\tleft: `${layout.x}px`,\n\t\ttop: `${layout.y}px`,\n\t\twidth: `${layout.width}px`,\n\t\theight: `${layout.height}px`,\n\t\t...(color === undefined ? {} : {background: color}),\n\t\tborderRadius: layout.kind === 'project' ? '3px' : '4px',\n\t\tcursor: readonly ? 'pointer' : 'grab',\n\t\tuserSelect: 'none',\n\t\toverflow: 'hidden',\n\t\tzIndex: selected ? '3' : '2',\n\t\ttouchAction: 'none',\n\t});\n\n\t// Progress overlay\n\tlet cleanupProgressDrag: (() => void) | undefined;\n\tif (layout.progressWidth > 0) {\n\t\tconst prog = el('div');\n\t\tconst progressEnabled = state.progressDragEnabled;\n\t\tcss(prog, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: '0',\n\t\t\ttop: '0',\n\t\t\twidth: `${layout.progressWidth}px`,\n\t\t\theight: '100%',\n\t\t\tbackground: 'rgba(0,0,0,0.18)',\n\t\t\t...(progressEnabled ? {cursor: 'ew-resize', touchAction: 'none'} : {pointerEvents: 'none'}),\n\t\t});\n\t\tif (progressEnabled) {\n\t\t\tprog.className = 'gantt-progress-overlay';\n\t\t\tcleanupProgressDrag = attachProgressDrag(prog, bar, task, () => state.mapper, cbs);\n\t\t}\n\t\tbar.append(prog);\n\t}\n\n\t// Label\n\tconst label = el('span');\n\tcss(label, {\n\t\tposition: 'absolute',\n\t\tleft: '8px',\n\t\tright: '8px',\n\t\ttop: '50%',\n\t\ttransform: 'translateY(-50%)',\n\t\toverflow: 'hidden',\n\t\ttextOverflow: 'ellipsis',\n\t\tcolor: 'var(--gantt-bar-label-color)',\n\t\tfontSize: 'var(--gantt-font-size-sm)',\n\t\tfontWeight: 'var(--gantt-font-weight-semibold)',\n\t\twhiteSpace: 'nowrap',\n\t\tpointerEvents: 'none',\n\t\ttextShadow: '0 1px 2px rgba(0,0,0,0.25)',\n\t});\n\tlabel.textContent = task.text;\n\tbar.append(label);\n\tbar.tabIndex = 0;\n\tbar.setAttribute('role', 'button');\n\tbar.setAttribute('aria-label', ariaLabel(state.locale, 'ariaTask', task.text));\n\tbar.setAttribute('aria-pressed', String(selected));\n\tbar.dataset['taskId'] = String(task.id);\n\tbar.addEventListener('click', (event) => {\n\t\tif (event.detail === 2) {\n\t\t\tcbs.onTaskDoubleClick?.({id: task.id, task: toTask(task)});\n\t\t} else {\n\t\t\tcbs.onTaskClick?.(task.id);\n\t\t}\n\t});\n\tbar.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onTaskClick?.(task.id);\n\t\t}\n\t});\n\n\tlet handle: HTMLElement | undefined;\n\tlet cleanupDrag: (() => void) | undefined;\n\n\tif (!readonly) {\n\t\t// Resize handle\n\t\thandle = el('div');\n\t\thandle.className = 'gantt-resize-handle';\n\t\tcss(handle, {\n\t\t\tposition: 'absolute',\n\t\t\tright: '0',\n\t\t\ttop: '0',\n\t\t\twidth: '8px',\n\t\t\theight: '100%',\n\t\t\tcursor: 'ew-resize',\n\t\t\tzIndex: '1',\n\t\t\ttouchAction: 'none',\n\t\t});\n\t\tbar.append(handle);\n\n\t\tlayer.insertBefore(bar, svgLayer);\n\t\tcleanupDrag = attachDrag(bar, handle, task, () => state.mapper, cbs);\n\t} else {\n\t\tlayer.insertBefore(bar, svgLayer);\n\t}\n\n\t// Link-creation endpoint handles\n\tlet cleanupLinkHandles: (() => void) | undefined;\n\tif (state.linkCreationEnabled) {\n\t\tconst barCenterY = layout.y + layout.height / 2;\n\t\tconst leftHandle = createEndpointHandle();\n\t\tleftHandle.style.left = `${layout.x}px`;\n\t\tleftHandle.style.top = `${barCenterY}px`;\n\t\tlayer.insertBefore(leftHandle, svgLayer);\n\n\t\tconst rightHandle = createEndpointHandle();\n\t\trightHandle.style.left = `${layout.x + layout.width}px`;\n\t\trightHandle.style.top = `${barCenterY}px`;\n\t\tlayer.insertBefore(rightHandle, svgLayer);\n\n\t\tconst cleanupLeft = attachLinkEndpointHandle(leftHandle, task.id, layout.x, barCenterY, svgLayer, layer, cbs);\n\t\tconst cleanupRight = attachLinkEndpointHandle(rightHandle, task.id, layout.x + layout.width, barCenterY, svgLayer, layer, cbs);\n\n\t\t// Show handles on bar hover\n\t\tconst onBarEnter = (): void => {\n\t\t\tleftHandle.style.opacity = '1';\n\t\t\trightHandle.style.opacity = '1';\n\t\t\tleftHandle.style.transform = 'translate(-50%, -50%) scale(1)';\n\t\t\trightHandle.style.transform = 'translate(-50%, -50%) scale(1)';\n\t\t};\n\t\tconst onBarLeave = (): void => {\n\t\t\tleftHandle.style.opacity = '0';\n\t\t\trightHandle.style.opacity = '0';\n\t\t\tleftHandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\t\t\trightHandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\t\t};\n\t\tbar.addEventListener('mouseenter', onBarEnter);\n\t\tbar.addEventListener('mouseleave', onBarLeave);\n\n\t\tcleanupLinkHandles = (): void => {\n\t\t\tcleanupLeft();\n\t\t\tcleanupRight();\n\t\t\tbar.removeEventListener('mouseenter', onBarEnter);\n\t\t\tbar.removeEventListener('mouseleave', onBarLeave);\n\t\t};\n\t}\n\n\t// Tooltip\n\tconst onTooltipEnter = (): void => {\n\t\tconst content = cbs.onTooltipText?.({id: task.id, task: toTask(task)});\n\t\tif (content && content.length > 0) {\n\t\t\ttooltipEl.innerHTML = content;\n\t\t\ttooltipEl.style.display = '';\n\t\t} else {\n\t\t\ttooltipEl.style.display = 'none';\n\t\t}\n\t};\n\tconst onTooltipMove = (e: MouseEvent): void => {\n\t\tconst offsetX = 12;\n\t\tconst offsetY = -8;\n\t\tlet left = e.clientX + offsetX;\n\t\tlet top = e.clientY + offsetY;\n\t\tconst maxLeft = window.innerWidth - tooltipEl.offsetWidth - 4;\n\t\tconst maxTop = window.innerHeight - tooltipEl.offsetHeight - 4;\n\t\tleft = Math.max(4, Math.min(left, maxLeft));\n\t\ttop = Math.max(4, Math.min(top, maxTop));\n\t\ttooltipEl.style.left = `${left}px`;\n\t\ttooltipEl.style.top = `${top}px`;\n\t};\n\tconst onTooltipLeave = (): void => {\n\t\ttooltipEl.style.display = 'none';\n\t};\n\tbar.addEventListener('mouseenter', onTooltipEnter);\n\tbar.addEventListener('mousemove', onTooltipMove);\n\tbar.addEventListener('mouseleave', onTooltipLeave);\n\tconst cleanupTooltip = (): void => {\n\t\tbar.removeEventListener('mouseenter', onTooltipEnter);\n\t\tbar.removeEventListener('mousemove', onTooltipMove);\n\t\tbar.removeEventListener('mouseleave', onTooltipLeave);\n\t};\n\n\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag?: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t\tcleanupProgressDrag?: () => void;\n\t\tcleanupTooltip?: () => void;\n\t} = {bar, resizeHandle: handle ?? el('div')};\n\tif (cleanupDrag !== undefined) {\n\t\tentry.cleanupDrag = cleanupDrag;\n\t}\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\n\t}\n\tif (cleanupProgressDrag !== undefined) {\n\t\tentry.cleanupProgressDrag = cleanupProgressDrag;\n\t}\n\tif (cleanupTooltip !== undefined) {\n\t\tentry.cleanupTooltip = cleanupTooltip;\n\t}\n\tregistry.set(task.id, entry);\n}\n\n// ─── Milestone ────────────────────────────────────────────────────────────────\n\nfunction renderMilestone(\n\tlayer: HTMLElement,\n\tsvgLayer: SVGSVGElement,\n\ttask: TaskNode,\n\tlayout: BarLayout,\n\tselectedId: number | null,\n\tregistry: RightPaneRefs['barRegistry'],\n\tcbs: RightPaneCallbacks,\n\tstate: GanttState,\n\ttooltipEl: HTMLElement,\n): void {\n\tconst selected = task.id === selectedId;\n\tconst readonly = task.readonly === true;\n\tconst size = MILESTONE_HALF * 2;\n\n\tconst diamond = el('div');\n\tdiamond.className = `gantt-milestone${selected ? ' gantt-shape--selected' : ''}`;\n\tcss(diamond, {\n\t\tposition: 'absolute',\n\t\tleft: `${layout.x - MILESTONE_HALF}px`,\n\t\ttop: `${layout.y + (layout.height - size) / 2}px`,\n\t\twidth: `${size}px`,\n\t\theight: `${size}px`,\n\t\tbackground: 'var(--gantt-milestone)',\n\t\ttransform: 'rotate(45deg)',\n\t\tcursor: readonly ? 'default' : 'pointer',\n\t\tzIndex: '4',\n\t});\n\tdiamond.tabIndex = 0;\n\tdiamond.setAttribute('role', 'button');\n\tdiamond.setAttribute('aria-label', ariaLabel(state.locale, 'ariaMilestone', task.text));\n\tdiamond.setAttribute('aria-pressed', String(selected));\n\tdiamond.dataset['taskId'] = String(task.id);\n\tdiamond.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onTaskClick?.(task.id);\n\t\t}\n\t});\n\tconst labelEl = el('span');\n\tcss(labelEl, {\n\t\tposition: 'absolute',\n\t\tleft: '50%',\n\t\ttop: '110%',\n\t\ttransform: 'translate(-50%, 0) rotate(-45deg)',\n\t\tfontSize: 'var(--gantt-font-size-xs)',\n\t\tfontWeight: 'var(--gantt-font-weight-semibold)',\n\t\tcolor: 'var(--gantt-milestone)',\n\t\twhiteSpace: 'nowrap',\n\t\tpointerEvents: 'none',\n\t});\n\tlabelEl.textContent = task.text;\n\tdiamond.append(labelEl);\n\n\tlayer.insertBefore(diamond, svgLayer);\n\tbindMilestoneTask(diamond, task);\n\n\t// Milestones have no resize handle — use a dummy div for the registry interface\n\tconst dummy = el('div');\n\tlet cleanupDrag: (() => void) | undefined;\n\n\tif (!readonly) {\n\t\tcleanupDrag = attachMilestoneClick(diamond, task.id, cbs);\n\t} else {\n\t\tdiamond.addEventListener('click', (event) => {\n\t\t\tif (event.detail === 2) {\n\t\t\t\tcbs.onTaskDoubleClick?.({id: task.id, task: toTask(task)});\n\t\t\t} else {\n\t\t\t\tcbs.onTaskClick?.(task.id);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Link-creation endpoint handle for milestones (single handle at center)\n\tlet cleanupLinkHandles: (() => void) | undefined;\n\tif (state.linkCreationEnabled) {\n\t\tconst diamondCenterY = layout.y + layout.height / 2;\n\t\tconst linkHandle = createEndpointHandle();\n\t\tlinkHandle.style.left = `${layout.x}px`;\n\t\tlinkHandle.style.top = `${diamondCenterY}px`;\n\t\tlinkHandle.style.background = 'var(--gantt-milestone)';\n\t\tlayer.insertBefore(linkHandle, svgLayer);\n\n\t\tconst cleanupLink = attachLinkEndpointHandle(linkHandle, task.id, layout.x, diamondCenterY, svgLayer, layer, cbs);\n\n\t\tconst onDiamondEnter = (): void => {\n\t\t\tlinkHandle.style.opacity = '1';\n\t\t\tlinkHandle.style.transform = 'translate(-50%, -50%) scale(1)';\n\t\t};\n\t\tconst onDiamondLeave = (): void => {\n\t\t\tlinkHandle.style.opacity = '0';\n\t\t\tlinkHandle.style.transform = 'translate(-50%, -50%) scale(0.8)';\n\t\t};\n\t\tdiamond.addEventListener('mouseenter', onDiamondEnter);\n\t\tdiamond.addEventListener('mouseleave', onDiamondLeave);\n\n\t\tcleanupLinkHandles = (): void => {\n\t\t\tcleanupLink();\n\t\t\tdiamond.removeEventListener('mouseenter', onDiamondEnter);\n\t\t\tdiamond.removeEventListener('mouseleave', onDiamondLeave);\n\t\t};\n\t}\n\n\t// Tooltip\n\tconst onTooltipEnter = (): void => {\n\t\tconst content = cbs.onTooltipText?.({id: task.id, task: toTask(task)});\n\t\tif (content && content.length > 0) {\n\t\t\ttooltipEl.innerHTML = content;\n\t\t\ttooltipEl.style.display = '';\n\t\t} else {\n\t\t\ttooltipEl.style.display = 'none';\n\t\t}\n\t};\n\tconst onTooltipMove = (e: MouseEvent): void => {\n\t\tconst offsetX = 12;\n\t\tconst offsetY = -8;\n\t\tlet left = e.clientX + offsetX;\n\t\tlet top = e.clientY + offsetY;\n\t\tconst maxLeft = window.innerWidth - tooltipEl.offsetWidth - 4;\n\t\tconst maxTop = window.innerHeight - tooltipEl.offsetHeight - 4;\n\t\tleft = Math.max(4, Math.min(left, maxLeft));\n\t\ttop = Math.max(4, Math.min(top, maxTop));\n\t\ttooltipEl.style.left = `${left}px`;\n\t\ttooltipEl.style.top = `${top}px`;\n\t};\n\tconst onTooltipLeave = (): void => {\n\t\ttooltipEl.style.display = 'none';\n\t};\n\tdiamond.addEventListener('mouseenter', onTooltipEnter);\n\tdiamond.addEventListener('mousemove', onTooltipMove);\n\tdiamond.addEventListener('mouseleave', onTooltipLeave);\n\tconst cleanupTooltip = (): void => {\n\t\tdiamond.removeEventListener('mouseenter', onTooltipEnter);\n\t\tdiamond.removeEventListener('mousemove', onTooltipMove);\n\t\tdiamond.removeEventListener('mouseleave', onTooltipLeave);\n\t};\n\n\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag?: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t\tcleanupProgressDrag?: () => void;\n\t\tcleanupTooltip?: () => void;\n\t} = {bar: diamond, resizeHandle: dummy};\n\tif (cleanupDrag !== undefined) {\n\t\tentry.cleanupDrag = cleanupDrag;\n\t}\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\n\t}\n\tif (cleanupTooltip !== undefined) {\n\t\tentry.cleanupTooltip = cleanupTooltip;\n\t}\n\tregistry.set(task.id, entry);\n}\n\n/**\n * Full render of the right pane.\n * Grid lines and stripes are rebuilt each call (cheap — no event listeners).\n * Bars are rebuilt each call with fresh drag listeners (old ones cleaned up first).\n *\n * @param refs - The right pane DOM references.\n * @param state - The current chart state.\n * @param cbs - The chart callbacks.\n */\nexport function renderRightPane(refs: RightPaneRefs, state: GanttState, cbs: RightPaneCallbacks): void {\n\tconst {\n\t\tallRows,\n\t\tlayouts,\n\t\tlinks,\n\t\tmapper,\n\t\tscale,\n\t\tviewportStart,\n\t\tviewportEnd,\n\t\ttotalWidth,\n\t\tselectedId,\n\t\thighlightLinkedDependenciesOnSelect,\n\t\tpaddingTop,\n\t\tpaddingBottom,\n\t\tstartIndex,\n\t} = state;\n\n\tconst {stripeContainer, absoluteLayer, svgLayer, barRegistry} = refs;\n\tconst rowCount = allRows.length;\n\tconst contentHeight = totalContentHeight(rowCount);\n\n\t// ── Stripe rows (virtual slice only) ───────────────────────────────────\n\tconst visibleRows = allRows.slice(state.startIndex, state.endIndex + 1);\n\tclearChildren(stripeContainer);\n\tcss(stripeContainer, {width: `${totalWidth}px`});\n\n\t// Top spacer\n\tif (paddingTop > 0) {\n\t\tconst s = el('div');\n\t\ts.style.height = `${paddingTop}px`;\n\t\tstripeContainer.append(s);\n\t}\n\n\tfor (let i = 0; i < visibleRows.length; i++) {\n\t\tconst rowIdx = startIndex + i;\n\t\tconst stripe = el('div');\n\t\tcss(stripe, {\n\t\t\theight: `${ROW_HEIGHT}px`,\n\t\t\tbackground: rowIdx % 2 === 0 ? 'var(--gantt-bg)' : 'var(--gantt-stripe)',\n\t\t\tborderBottom: '1px solid var(--gantt-border)',\n\t\t});\n\t\tstripeContainer.append(stripe);\n\t}\n\n\t// Bottom spacer\n\tif (paddingBottom > 0) {\n\t\tconst s = el('div');\n\t\ts.style.height = `${paddingBottom}px`;\n\t\tstripeContainer.append(s);\n\t}\n\n\t// ── Absolute layer: grid lines + today + bars ──────────────────────────\n\tcss(absoluteLayer, {width: `${totalWidth}px`, height: `${contentHeight}px`});\n\n\t// Remove all children except svgLayer (last child)\n\tconst toRemove: Element[] = [];\n\tfor (const child of [...absoluteLayer.children]) {\n\t\tif (child !== svgLayer) {\n\t\t\ttoRemove.push(child);\n\t\t}\n\t}\n\tfor (const node of toRemove) {\n\t\tabsoluteLayer.removeChild(node);\n\t}\n\n\t// Clean up orphaned ghost line from interrupted drags\n\thideGhostLine(svgLayer);\n\n\t// Clean up previous drag listeners\n\tfor (const {cleanupDrag, cleanupLinkHandles, cleanupProgressDrag} of barRegistry.values()) {\n\t\tcleanupDrag?.();\n\t\tcleanupLinkHandles?.();\n\t\tcleanupProgressDrag?.();\n\t}\n\tbarRegistry.clear();\n\n\t// Special day backgrounds (day scale only)\n\tif (scale === 'day') {\n\t\trenderSpecialDayBackgrounds(absoluteLayer, svgLayer, state, contentHeight);\n\t}\n\n\t// Grid lines\n\tlet gridCur = snapToScaleBoundary(viewportStart, scale);\n\twhile (gridCur <= viewportEnd) {\n\t\tconst x = mapper.toX(gridCur);\n\t\tconst line = el('div');\n\t\tcss(line, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${x}px`,\n\t\t\ttop: '0',\n\t\t\twidth: '1px',\n\t\t\theight: `${contentHeight}px`,\n\t\t\tbackground: 'var(--gantt-grid-line)',\n\t\t\tpointerEvents: 'none',\n\t\t});\n\t\tabsoluteLayer.insertBefore(line, svgLayer);\n\t\tgridCur = nextScaleBoundary(gridCur, scale);\n\t}\n\n\t// Today marker (render only when enabled and within timeline bounds)\n\tconst todayX = mapper.toX(new Date());\n\tconst todayLineWidth = 2;\n\tif (state.showTodayMarker && todayX >= 0 && todayX <= totalWidth - todayLineWidth) {\n\t\tconst todayLine = el('div');\n\t\ttodayLine.className = 'gantt-today-marker';\n\t\tcss(todayLine, {\n\t\t\tposition: 'absolute',\n\t\t\tleft: `${todayX}px`,\n\t\t\ttop: '0',\n\t\t\twidth: `${todayLineWidth}px`,\n\t\t\theight: `${contentHeight}px`,\n\t\t\tbackground: 'var(--gantt-today)',\n\t\t\tpointerEvents: 'none',\n\t\t\tzIndex: '5',\n\t\t});\n\t\tabsoluteLayer.insertBefore(todayLine, svgLayer);\n\t}\n\n\tconst visibleTaskIds = new Set(visibleRows.map((task) => task.id));\n\n\t// Bars (virtual slice only)\n\tfor (const task of visibleRows) {\n\t\tconst layout = layouts.get(task.id);\n\t\tif (layout === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (layout.kind === 'milestone') {\n\t\t\trenderMilestone(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, cbs, state, refs.tooltipEl);\n\t\t} else {\n\t\t\trenderBar(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, state, cbs, refs.tooltipEl);\n\t\t}\n\t}\n\n\t// SVG dependency overlay (visible rows only)\n\tconst visibleLinks = links.filter((link) => visibleTaskIds.has(link.sourceTaskId) && visibleTaskIds.has(link.targetTaskId));\n\tupdateDependencyLayer(svgLayer, visibleLinks, totalWidth, contentHeight, selectedId, highlightLinkedDependenciesOnSelect, cbs);\n}\n","import {SpecialDaySchema, type _GanttInputZod as GanttInput, type SpecialDay} from '../validation/schemas.ts';\nimport {parseDate} from '../domain/dateMath.ts';\nimport {buildTaskTree} from '../domain/tree.ts';\nimport {type ResolvedSpecialDay} from './state.ts';\n\nexport function buildTaskIndex(tasks: GanttInput['tasks']): Map<number, number> {\n\tconst index = new Map<number, number>();\n\tfor (let i = 0; i < tasks.length; i++) {\n\t\tconst task = tasks[i];\n\t\tif (task !== undefined) {\n\t\t\tindex.set(task.id, i);\n\t\t}\n\t}\n\treturn index;\n}\n\nexport function toIsoDate(date: Date): string {\n\treturn date.toISOString().slice(0, 10);\n}\n\nexport function buildSpecialDayIndex(specialDays: SpecialDay[]): Map<string, ResolvedSpecialDay> {\n\tconst map = new Map<string, ResolvedSpecialDay>();\n\tfor (const specialDay of specialDays) {\n\t\tconst parsed = SpecialDaySchema.parse(specialDay);\n\t\tconst isoDate = toIsoDate(parseDate(parsed.date));\n\t\tmap.set(isoDate, {\n\t\t\tkind: parsed.kind,\n\t\t\t...(parsed.label === undefined ? {} : {label: parsed.label}),\n\t\t\t...(parsed.className === undefined ? {} : {className: parsed.className}),\n\t\t});\n\t}\n\treturn map;\n}\n\nexport function normalizeWeekendDays(days: number[] | undefined): Set<number> {\n\tif (days === undefined) {\n\t\treturn new Set([0, 6]);\n\t}\n\n\tconst normalized = new Set<number>();\n\tfor (const day of days) {\n\t\tif (!Number.isInteger(day) || day < 0 || day > 6) {\n\t\t\tthrow new Error('weekendDays must contain integers in range 0..6');\n\t\t}\n\t\tnormalized.add(day);\n\t}\n\treturn normalized;\n}\n\nexport function getExpandableTaskIds(tasks: GanttInput['tasks']): Set<number> {\n\tconst roots = buildTaskTree(tasks);\n\tconst expandableIds = new Set<number>();\n\tconst stack = [...roots];\n\twhile (stack.length > 0) {\n\t\tconst node = stack.pop();\n\t\tif (node === undefined) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (node.children.length > 0) {\n\t\t\texpandableIds.add(node.id);\n\t\t}\n\t\tfor (const child of node.children) {\n\t\t\tstack.push(child);\n\t\t}\n\t}\n\treturn expandableIds;\n}\n\nexport function getInitialExpandedIds(tasks: GanttInput['tasks']): Set<number> {\n\tconst expandableIds = getExpandableTaskIds(tasks);\n\tconst expandedIds = new Set<number>();\n\tfor (const task of tasks) {\n\t\tif (task.kind === 'project' && task.open && expandableIds.has(task.id)) {\n\t\t\texpandedIds.add(task.id);\n\t\t}\n\t}\n\treturn expandedIds;\n}\n","const MIN_PANE_WIDTH = 96;\n\nexport function attachSplitter(\n\tsplitterHandle: HTMLElement,\n\tleftPane: HTMLElement,\n\tcontainer: HTMLElement,\n\ttimelineMinWidth: number,\n\tonDragEnd: (width: number) => void,\n): void {\n\tsplitterHandle.addEventListener('pointerdown', (e: PointerEvent) => {\n\t\tif (e.button !== 0) {\n\t\t\treturn;\n\t\t}\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tconst startX = e.clientX;\n\t\tconst startWidth = Number.parseFloat(leftPane.style.width) || 0;\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tlet newWidth = startWidth + dx;\n\t\t\tconst hostWidth = container.clientWidth;\n\t\t\tif (hostWidth > 0) {\n\t\t\t\tnewWidth = Math.max(MIN_PANE_WIDTH, Math.min(newWidth, hostWidth - timelineMinWidth));\n\t\t\t}\n\t\t\tnewWidth = Math.max(MIN_PANE_WIDTH, newWidth);\n\t\t\tleftPane.style.width = `${newWidth}px`;\n\t\t\tleftPane.style.minWidth = `${newWidth}px`;\n\t\t\tleftPane.style.maxWidth = `${newWidth}px`;\n\t\t}\n\n\t\tfunction onUp(): void {\n\t\t\twindow.removeEventListener('pointermove', onMove);\n\t\t\twindow.removeEventListener('pointerup', onUp);\n\t\t\tconst finalWidth = Number.parseFloat(leftPane.style.width);\n\t\t\tonDragEnd(finalWidth);\n\t\t}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t});\n}\n","export const MOBILE_BREAKPOINT = 768;\nexport const MOBILE_LEFT_PANE_MIN_WIDTH = 140;\nexport const MOBILE_LEFT_PANE_MAX_RATIO = 0.45;\nexport const TIMELINE_MIN_WIDTH = 220;\nexport const DESKTOP_MIN_RATIO = 0.25;\nexport const DESKTOP_MAX_RATIO = 0.4;\nconst MIN_PANE_WIDTH = 96;\n\nexport type ComputeLeftPaneWidthOptions = {\n\thostWidth: number;\n\tdefaultWidth: number;\n\tuserSplitWidth: number | null;\n\texplicitOptWidth: number | undefined;\n\tresponsiveSplitPane: boolean;\n\tmobileBreakpoint: number;\n\tmobileLeftPaneMinWidth: number;\n\tmobileLeftPaneMaxRatio: number;\n\ttimelineMinWidth: number;\n};\n\nexport function computeLeftPaneWidth(options: ComputeLeftPaneWidthOptions): number {\n\tconst {\n\t\thostWidth,\n\t\tdefaultWidth,\n\t\tuserSplitWidth,\n\t\texplicitOptWidth,\n\t\tresponsiveSplitPane,\n\t\tmobileBreakpoint,\n\t\tmobileLeftPaneMinWidth,\n\t\tmobileLeftPaneMaxRatio,\n\t\ttimelineMinWidth,\n\t} = options;\n\n\tlet width = defaultWidth;\n\n\tif (hostWidth <= 0) {\n\t\treturn width;\n\t}\n\n\tif (userSplitWidth !== null) {\n\t\twidth = userSplitWidth;\n\t} else if (explicitOptWidth !== undefined) {\n\t\twidth = explicitOptWidth;\n\t} else if (responsiveSplitPane && hostWidth <= mobileBreakpoint) {\n\t\tconst ratioWidth = Math.floor(hostWidth * mobileLeftPaneMaxRatio);\n\t\twidth = Math.min(defaultWidth, Math.max(mobileLeftPaneMinWidth, ratioWidth));\n\t} else {\n\t\tconst minProportional = Math.floor(hostWidth * DESKTOP_MIN_RATIO);\n\t\tconst maxProportional = Math.floor(hostWidth * DESKTOP_MAX_RATIO);\n\t\twidth = Math.min(maxProportional, Math.max(defaultWidth, minProportional));\n\t}\n\n\tconst maxAllowed = Math.max(MIN_PANE_WIDTH, hostWidth - timelineMinWidth);\n\twidth = Math.min(width, maxAllowed);\n\n\treturn Math.max(MIN_PANE_WIDTH, Math.floor(width));\n}\n","import {\n\ttype _GanttInputZod,\n\ttype GanttInputRaw,\n\tGanttInputSchema,\n\ttype SpecialDay,\n\ttype ZodTaskInferred,\n\ttype Task as GenTask,\n\ttype Link as GenLink,\n} from '../validation/schemas.ts';\nimport {validateLinkRefs, detectCycles} from '../domain/dependencies.ts';\nimport {buildTaskTree, flattenTree} from '../domain/tree.ts';\nimport {createPixelMapper} from '../timeline/pixelMapper.ts';\nimport {computeLayout, deriveViewport, ROW_HEIGHT} from '../timeline/layoutEngine.ts';\nimport {routeLinks} from '../rendering/linkRouter.ts';\nimport {ceilToScaleBoundary, type TimeScale} from '../timeline/scale.ts';\nimport {type GanttState, type ResolvedSpecialDay} from './state.ts';\nimport {el, css, clearChildren} from './dom/helpers.ts';\nimport {renderTimeHeader} from './dom/timeHeader.ts';\nimport {renderLeftPane, buildLeftPaneHeader, setupColumnResize} from './dom/leftPane.ts';\nimport {createRightPaneRefs, renderRightPane} from './dom/rightPane.ts';\nimport {type RightPaneRefs} from './dom/rightPane.ts';\nimport {type GridColumn, gridNaturalWidth, gridColumnDefaults} from './dom/gridColumns.ts';\nimport {parseDate, diffHours} from '../domain/dateMath.ts';\nimport {GanttError} from '../errors.ts';\nimport {buildTaskIndex, buildSpecialDayIndex, normalizeWeekendDays, getExpandableTaskIds, getInitialExpandedIds} from './utils.ts';\nimport {attachSplitter} from './splitter.ts';\nimport {computeLeftPaneWidth, MOBILE_BREAKPOINT, MOBILE_LEFT_PANE_MIN_WIDTH, MOBILE_LEFT_PANE_MAX_RATIO, TIMELINE_MIN_WIDTH} from './responsive.ts';\nimport {type ChartLocale, resolveChartLocale} from '../locale.ts';\n\n/** Internal convenience aliases for the zod-inferred runtime types (include `data?: Record<string, unknown>`). */\ntype GanttInput = _GanttInputZod;\ntype Task = ZodTaskInferred;\n\nexport type OnTaskClick<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnTaskDoubleClick<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnTaskMove<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tnewStartDate: Date;\n\tnewEndDate: Date;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnTaskResize<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tnewDurationHours: number;\n\tnewStartDate: Date;\n\tnewEndDate: Date;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnTaskAdd<TTaskData = never, TLinkData = never> = (payload: {\n\tparentTask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnLinkCreate<TTaskData = never, TLinkData = never> = (payload: {\n\ttype: 'FS';\n\tsourceTask: GenTask<TTaskData>;\n\ttargetTask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnLinkClick<TTaskData = never, TLinkData = never> = (payload: {\n\tlink: GenLink<TLinkData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnLinkDblClick<TTaskData = never, TLinkData = never> = (payload: {\n\tlink: GenLink<TLinkData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnProgressChange<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tnewPercentComplete: number;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => boolean | Promise<boolean>;\nexport type OnExpandCollapse<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnExpandCollapseAll<TTaskData = never, TLinkData = never> = (payload: {\n\ttasks: GenTask<TTaskData>[];\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => void | Promise<void>;\nexport type OnTooltipText<TTaskData = never, TLinkData = never> = (payload: {\n\ttask: GenTask<TTaskData>;\n\tinstance: GanttInstance<TTaskData, TLinkData>;\n}) => string | null;\n\nexport type GanttCallbacks<TTaskData = never, TLinkData = never> = {\n\tonTaskClick?: OnTaskClick<TTaskData, TLinkData>;\n\tonTaskDoubleClick?: OnTaskDoubleClick<TTaskData, TLinkData>;\n\tonTaskMove?: OnTaskMove<TTaskData, TLinkData>;\n\tonTaskResize?: OnTaskResize<TTaskData, TLinkData>;\n\tonTaskAdd?: OnTaskAdd<TTaskData, TLinkData>;\n\tonLinkCreate?: OnLinkCreate<TTaskData, TLinkData>;\n\tonLinkClick?: OnLinkClick<TTaskData, TLinkData>;\n\tonLinkDblClick?: OnLinkDblClick<TTaskData, TLinkData>;\n\tonProgressChange?: OnProgressChange<TTaskData, TLinkData>;\n\tonExpandCollapse?: OnExpandCollapse<TTaskData, TLinkData>;\n\tonExpandCollapseAll?: OnExpandCollapseAll<TTaskData, TLinkData>;\n\tonTooltipText?: OnTooltipText<TTaskData, TLinkData>;\n\tonLeftPaneWidthChange?: (payload: {width: number; instance: GanttInstance<TTaskData, TLinkData>}) => void | Promise<void>;\n\tonGridColumnsChange?: (payload: {columns: GridColumn[]; instance: GanttInstance<TTaskData, TLinkData>}) => void | Promise<void>;\n};\n\ntype InternalCallbacks = {\n\tonTaskClick?: (id: number) => void;\n\tonTaskMove?: (payload: {id: number; startDate: Date}) => void;\n\t_onTaskMoveFinal?: (payload: {id: number; startDate: Date}) => Promise<boolean>;\n\tonTaskResize?: (payload: {id: number; endDate: string}) => void;\n\t_onTaskResizeFinal?: (payload: {id: number; endDate: string}) => Promise<boolean>;\n\tonTaskAdd?: (parentId: number) => void;\n\tonTaskEditIntent?: (payload: {id: number; source: 'grid' | 'bar' | 'milestone'; trigger: 'doubleClick'; task: Task}) => void;\n\tonTaskDoubleClick?: (payload: {id: number; task: Task}) => void;\n\tonLinkCreate?: (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n\tonLinkClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonLinkDblClick?: (payload: {id: number; source: number; target: number; type: string}) => void;\n\tonTaskProgressDrag?: (payload: {id: number; percentComplete: number}) => void;\n\t_onTaskProgressDragFinal?: (payload: {id: number; percentComplete: number}) => Promise<boolean>;\n\tonTooltipText?: (payload: {id: number; task: Task}) => string | null;\n\tonLeftPaneWidthChange?: (width: number) => void;\n\tonGridColumnsChange?: (columns: GridColumn[]) => void;\n};\n\nexport type ThemeMode = 'light' | 'dark' | 'system';\n\nexport type GanttOptions = {\n\tscale?: TimeScale;\n\thighlightLinkedDependenciesOnSelect?: boolean;\n\tlinkCreationEnabled?: boolean;\n\tprogressDragEnabled?: boolean;\n\tleftPaneWidth?: number;\n\tresponsiveSplitPane?: boolean;\n\tmobileBreakpoint?: number;\n\tmobileLeftPaneMinWidth?: number;\n\tmobileLeftPaneMaxRatio?: number;\n\ttimelineMinWidth?: number;\n\theight?: number;\n\tviewportStart?: Date;\n\tviewportEnd?: Date;\n\tlocale?: ChartLocale | string;\n\tshowWeekends?: boolean;\n\tweekendDays?: number[];\n\tspecialDays?: SpecialDay[];\n\tgridColumns?: GridColumn[];\n\ttheme?: ThemeMode;\n\tshowAddTaskButton?: boolean;\n\tshowTodayMarker?: boolean;\n};\n\nexport type GanttInstance<TTaskData = never, TLinkData = never> = {\n\tupdate: (input: GanttInputRaw<TTaskData, TLinkData>) => void;\n\tsetOptions: (opts: Partial<GanttOptions>) => void;\n\tsetCallbacks: (cbs: GanttCallbacks<TTaskData, TLinkData>) => void;\n\tselect: (id: number | null, fireCallback?: boolean) => void;\n\tcollapseAll: (fireCallback?: boolean) => void;\n\texpandAll: (fireCallback?: boolean) => void;\n\tgetOpenStates: () => {id: number; open: boolean}[];\n\tdestroy: () => void;\n};\n\nconst HEADER_H = 52;\nconst OVERSCAN = 4;\n\n/**\n * Progressive-enhancement Gantt chart component.\n * Validates input, builds a DOM tree, and renders a full interactive chart\n * inside the given container element.\n *\n * @param TTaskData - The type of the optional `data` property on tasks. Defaults to `never`.\n * @param TLinkData - The type of the optional `data` property on links. Defaults to `never`.\n *\n * @example\n * ```ts\n * const chart = new GanttChart(document.getElementById('chart')!, {\n * locale: 'de-DE',\n * theme: 'dark',\n * });\n * ```\n */\nexport class GanttChart<TTaskData = never, TLinkData = never> implements GanttInstance<TTaskData, TLinkData> {\n\treadonly #container: HTMLElement;\n\treadonly #opts: GanttOptions;\n\t#callbacks: GanttCallbacks<TTaskData, TLinkData>;\n\t#input: GanttInput | null = null;\n\t#scale: TimeScale;\n\t#selectedId: number | null = null;\n\t#scrollTop = 0;\n\t#rafPending = false;\n\t#rafId: number | null = null;\n\t#destroyed = false;\n\treadonly #dragOriginals = new Map<number, Task>();\n\t#taskIndex: Map<number, number>;\n\t#lastGridClick: {id: number; atMs: number} | null = null;\n\t#userSplitWidth: number | null = null;\n\n\t#height: number;\n\t#locale: ChartLocale;\n\t#timelineMinWidth: number;\n\t#columns: GridColumn[];\n\t#leftPaneDefaultWidth: number;\n\t#showAddTaskButton: boolean;\n\t#weekendDays: Set<number>;\n\t#specialDaysByDate: Map<string, ResolvedSpecialDay>;\n\t#expandedIds: Set<number>;\n\n\t// oxlint-disable typescript-eslint(prefer-readonly)\n\t#root!: HTMLElement;\n\t#scrollEl!: HTMLElement;\n\t#leftPane!: HTMLElement;\n\t#leftHeader!: HTMLElement;\n\t#leftBody!: HTMLElement;\n\t#rightPane!: HTMLElement;\n\t#rightHeader!: HTMLElement;\n\t#rightPaneRefs!: RightPaneRefs;\n\t#cbs: InternalCallbacks;\n\n\t#resizeObserver: ResizeObserver | null = null;\n\t#columnResizeCleanup!: () => void;\n\n\t/**\n\t * Constructs a new chart, builds the DOM, and wires internal event handling.\n\t * Data must be loaded via {@link update} before the chart renders.\n\t * Callbacks must be set via {@link setCallbacks} before user interactions are handled.\n\t *\n\t * @param container - The host `HTMLElement` the chart will be appended to.\n\t * @param opts - Configuration options.\n\t */\n\tpublic constructor(container: HTMLElement, opts: GanttOptions = {}) {\n\t\tthis.#container = container;\n\n\t\tthis.#scale = opts.scale ?? 'day';\n\t\tthis.#opts = opts;\n\t\tthis.#callbacks = {};\n\t\tthis.#taskIndex = new Map();\n\t\tthis.#locale = resolveChartLocale(opts.locale);\n\t\tthis.#columns = opts.gridColumns ?? gridColumnDefaults(this.#locale);\n\t\tthis.#showAddTaskButton = opts.showAddTaskButton ?? true;\n\t\tthis.#syncActionsColumnVisibility();\n\t\tthis.#leftPaneDefaultWidth = opts.leftPaneWidth ?? gridNaturalWidth(this.#columns);\n\t\tthis.#height = opts.height ?? 500;\n\t\tthis.#timelineMinWidth = opts.timelineMinWidth ?? TIMELINE_MIN_WIDTH;\n\t\tthis.#weekendDays = normalizeWeekendDays(opts.weekendDays ?? this.#locale.weekendDays);\n\t\tthis.#specialDaysByDate = buildSpecialDayIndex(opts.specialDays ?? []);\n\t\tthis.#expandedIds = new Set();\n\n\t\tthis.#cbs = this.#buildCallbackAdapter();\n\n\t\tthis.#buildDom();\n\t\tthis.#wireEvents();\n\n\t\tcontainer.append(this.#root);\n\n\t\tthis.#applyTheme();\n\n\t\tthis.#applyResponsivePaneStyles();\n\t\tthis.#setupResizeObserver();\n\t}\n\n\t#buildCallbackAdapter(this: GanttChart<TTaskData, TLinkData>): InternalCallbacks {\n\t\treturn {\n\t\t\tonTaskClick: (id): void => {\n\t\t\t\tif (this.#selectedId === id) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.#selectedId = id;\n\t\t\t\tif (this.#selectedId !== null) {\n\t\t\t\t\tconst task = this.#findTask(this.#selectedId);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tvoid this.#callbacks.onTaskClick?.({task: task as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonTaskDoubleClick: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onTaskDoubleClick?.({task: payload.task as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t},\n\t\t\tonTaskEditIntent: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onTaskDoubleClick?.({task: payload.task as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t},\n\t\t\tonTaskMove: (payload): void => {\n\t\t\t\tif (!this.#dragOriginals.has(payload.id)) {\n\t\t\t\t\tconst task = this.#input?.tasks.find((t) => t.id === payload.id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tthis.#dragOriginals.set(payload.id, task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst iso = payload.startDate.toISOString().slice(0, 10);\n\t\t\t\tthis.#patchTask(payload.id, {startDate: iso});\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\t_onTaskMoveFinal: async (payload): Promise<boolean> => {\n\t\t\t\tconst task = this.#findTask(payload.id);\n\t\t\t\tif (task !== undefined) {\n\t\t\t\t\tconst newEndDate = task.kind !== 'milestone' ? parseDate(task.endDate) : payload.startDate;\n\t\t\t\t\tconst result = this.#callbacks.onTaskMove?.({\n\t\t\t\t\t\ttask: task as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tnewStartDate: payload.startDate,\n\t\t\t\t\t\tnewEndDate,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t\tif (!(await result)) {\n\t\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\t\tif (original !== undefined) {\n\t\t\t\t\t\t\t\tthis.#patchTask(payload.id, {startDate: original.startDate});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!result) {\n\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\tif (original !== undefined) {\n\t\t\t\t\t\t\tthis.#patchTask(payload.id, {startDate: original.startDate});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#dragOriginals.clear();\n\t\t\t\tthis.#scheduleRender();\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tonTaskResize: (payload): void => {\n\t\t\t\tif (!this.#dragOriginals.has(payload.id)) {\n\t\t\t\t\tconst task = this.#input?.tasks.find((t) => t.id === payload.id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tthis.#dragOriginals.set(payload.id, task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#patchTask(payload.id, {endDate: payload.endDate});\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\t_onTaskResizeFinal: async (payload): Promise<boolean> => {\n\t\t\t\tconst task = this.#findTask(payload.id);\n\t\t\t\tif (task !== undefined && task.kind !== 'milestone') {\n\t\t\t\t\tconst newStartDate = parseDate(task.startDate);\n\t\t\t\t\tconst newEndDate = parseDate(task.endDate);\n\t\t\t\t\tconst newDurationHours = diffHours(newEndDate, newStartDate);\n\t\t\t\t\tconst result = this.#callbacks.onTaskResize?.({\n\t\t\t\t\t\ttask: task as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tnewDurationHours,\n\t\t\t\t\t\tnewStartDate,\n\t\t\t\t\t\tnewEndDate,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t\tif (!(await result)) {\n\t\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\t\tthis.#patchTask(payload.id, {endDate: original.endDate});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!result) {\n\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\tthis.#patchTask(payload.id, {endDate: original.endDate});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#dragOriginals.clear();\n\t\t\t\tthis.#scheduleRender();\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tonTaskProgressDrag: (payload): void => {\n\t\t\t\tif (!this.#dragOriginals.has(payload.id)) {\n\t\t\t\t\tconst task = this.#input?.tasks.find((t) => t.id === payload.id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tthis.#dragOriginals.set(payload.id, task);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#patchTask(payload.id, {percentComplete: payload.percentComplete});\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\t_onTaskProgressDragFinal: async (payload): Promise<boolean> => {\n\t\t\t\tconst task = this.#findTask(payload.id);\n\t\t\t\tif (task !== undefined) {\n\t\t\t\t\tconst result = this.#callbacks.onProgressChange?.({\n\t\t\t\t\t\ttask: task as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tnewPercentComplete: payload.percentComplete,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t\tif (result instanceof Promise) {\n\t\t\t\t\t\tif (!(await result)) {\n\t\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\t\tthis.#patchTask(payload.id, {percentComplete: original.percentComplete});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (!result) {\n\t\t\t\t\t\tconst original = this.#dragOriginals.get(payload.id);\n\t\t\t\t\t\tif (original !== undefined && original.kind !== 'milestone') {\n\t\t\t\t\t\t\tthis.#patchTask(payload.id, {percentComplete: original.percentComplete});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.#dragOriginals.clear();\n\t\t\t\tthis.#scheduleRender();\n\t\t\t\treturn true;\n\t\t\t},\n\t\t\tonTaskAdd: (parentId): void => {\n\t\t\t\tconst parentTask = this.#findTask(parentId);\n\t\t\t\tif (parentTask !== undefined) {\n\t\t\t\t\tvoid this.#callbacks.onTaskAdd?.({parentTask: parentTask as unknown as GenTask<TTaskData>, instance: this});\n\t\t\t\t}\n\t\t\t},\n\t\t\tonLeftPaneWidthChange: (width): void => {\n\t\t\t\tvoid this.#callbacks.onLeftPaneWidthChange?.({width, instance: this});\n\t\t\t},\n\t\t\tonGridColumnsChange: (updatedColumns): void => {\n\t\t\t\tvoid this.#callbacks.onGridColumnsChange?.({columns: updatedColumns, instance: this});\n\t\t\t},\n\t\t\tonLinkCreate: (payload): void => {\n\t\t\t\tconst sourceTask = this.#findTask(payload.sourceTaskId);\n\t\t\t\tconst targetTask = this.#findTask(payload.targetTaskId);\n\t\t\t\tif (sourceTask !== undefined && targetTask !== undefined) {\n\t\t\t\t\tvoid this.#callbacks.onLinkCreate?.({\n\t\t\t\t\t\ttype: 'FS',\n\t\t\t\t\t\tsourceTask: sourceTask as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\ttargetTask: targetTask as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\tonLinkClick: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onLinkClick?.({link: payload as unknown as GenLink<TLinkData>, instance: this});\n\t\t\t},\n\t\t\tonLinkDblClick: (payload): void => {\n\t\t\t\tvoid this.#callbacks.onLinkDblClick?.({link: payload as unknown as GenLink<TLinkData>, instance: this});\n\t\t\t},\n\t\t\tonTooltipText: (payload): string | null => this.#callbacks.onTooltipText?.({task: payload.task as unknown as GenTask<TTaskData>, instance: this}) ?? null,\n\t\t};\n\t}\n\n\t/**\n\t * Sets or replaces the chart's user-facing callbacks.\n\t * Does not trigger a re-render.\n\t *\n\t * @param cbs - The {@link GanttCallbacks} to register.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic setCallbacks(cbs: GanttCallbacks<TTaskData, TLinkData>): void {\n\t\tthis.#assertAlive();\n\t\tthis.#callbacks = cbs;\n\t\tthis.#cbs = this.#buildCallbackAdapter();\n\t}\n\n\t/**\n\t * Replaces the full dataset and re-renders.\n\t *\n\t * @param newInput - The new {@link GanttInput} to apply.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic update(newInput: GanttInputRaw<TTaskData, TLinkData>): void {\n\t\tthis.#assertAlive();\n\t\tconst input = GanttInputSchema.parse(newInput) as unknown as GanttInput;\n\t\tvalidateLinkRefs(input.tasks, input.links);\n\t\tdetectCycles(input.tasks, input.links);\n\t\tthis.#input = structuredClone(input);\n\t\tthis.#taskIndex = buildTaskIndex(this.#input.tasks);\n\t\tthis.#expandedIds = getInitialExpandedIds(this.#input.tasks);\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t}\n\n\t/**\n\t * Merges the supplied options into the current configuration and re-renders\n\t * only the panes affected by the changed options.\n\t *\n\t * @param opts - A partial {@link GanttOptions} object. Only the keys present\n\t * in this parameter are updated; missing keys keep their\n\t * previous values.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic setOptions(opts: Partial<GanttOptions>): void {\n\t\tthis.#assertAlive();\n\n\t\tObject.assign(this.#opts, opts);\n\n\t\tthis.#scale = this.#opts.scale ?? 'day';\n\n\t\tlet columnsChanged = false;\n\n\t\tif (opts.locale !== undefined) {\n\t\t\tthis.#locale = resolveChartLocale(opts.locale);\n\t\t\tif (this.#opts.gridColumns === undefined) {\n\t\t\t\tthis.#columns = gridColumnDefaults(this.#locale);\n\t\t\t\tthis.#leftPaneDefaultWidth = gridNaturalWidth(this.#columns);\n\t\t\t\tcolumnsChanged = true;\n\t\t\t}\n\t\t\tif (this.#opts.weekendDays === undefined) {\n\t\t\t\tthis.#weekendDays = normalizeWeekendDays(this.#locale.weekendDays);\n\t\t\t}\n\t\t}\n\n\t\tif (opts.gridColumns !== undefined) {\n\t\t\tthis.#columns = opts.gridColumns;\n\t\t\tthis.#leftPaneDefaultWidth = this.#opts.leftPaneWidth ?? gridNaturalWidth(this.#columns);\n\t\t\tcolumnsChanged = true;\n\t\t}\n\n\t\tif (columnsChanged && this.#input !== null) {\n\t\t\tthis.#rebuildLeftPaneHeader();\n\t\t}\n\n\t\tif (opts.leftPaneWidth !== undefined) {\n\t\t\tthis.#leftPaneDefaultWidth = opts.leftPaneWidth;\n\t\t}\n\n\t\tif (opts.height !== undefined) {\n\t\t\tthis.#height = opts.height;\n\t\t\tthis.#root.style.height = `${this.#height}px`;\n\t\t}\n\n\t\tif (opts.timelineMinWidth !== undefined) {\n\t\t\tthis.#timelineMinWidth = opts.timelineMinWidth;\n\t\t\tthis.#rightPane.style.minWidth = `${this.#timelineMinWidth}px`;\n\t\t}\n\n\t\tif (opts.weekendDays !== undefined) {\n\t\t\tthis.#weekendDays = normalizeWeekendDays(opts.weekendDays);\n\t\t}\n\n\t\tif (opts.specialDays !== undefined) {\n\t\t\tthis.#specialDaysByDate = buildSpecialDayIndex(opts.specialDays);\n\t\t}\n\n\t\tif (opts.theme !== undefined) {\n\t\t\tthis.#applyTheme();\n\t\t}\n\n\t\tif (opts.showAddTaskButton !== undefined) {\n\t\t\tthis.#showAddTaskButton = opts.showAddTaskButton;\n\t\t\tthis.#syncActionsColumnVisibility();\n\t\t\tconst naturalWidth = gridNaturalWidth(this.#columns);\n\t\t\tif (naturalWidth !== this.#leftPaneDefaultWidth) {\n\t\t\t\tthis.#leftPaneDefaultWidth = naturalWidth;\n\t\t\t\tcolumnsChanged = true;\n\t\t\t\tthis.#rebuildLeftPaneHeader();\n\t\t\t}\n\t\t}\n\n\t\tconst hasLayoutChange =\n\t\t\topts.leftPaneWidth !== undefined ||\n\t\t\topts.responsiveSplitPane !== undefined ||\n\t\t\topts.mobileBreakpoint !== undefined ||\n\t\t\topts.mobileLeftPaneMinWidth !== undefined ||\n\t\t\topts.mobileLeftPaneMaxRatio !== undefined ||\n\t\t\topts.timelineMinWidth !== undefined;\n\n\t\tif (hasLayoutChange) {\n\t\t\tthis.#applyResponsivePaneStyles();\n\t\t}\n\n\t\tconst hasLeftPaneChange = columnsChanged || opts.locale !== undefined || opts.showAddTaskButton !== undefined;\n\n\t\tconst hasRightPaneChange =\n\t\t\topts.scale !== undefined ||\n\t\t\topts.showTodayMarker !== undefined ||\n\t\t\topts.showWeekends !== undefined ||\n\t\t\topts.weekendDays !== undefined ||\n\t\t\topts.specialDays !== undefined ||\n\t\t\topts.highlightLinkedDependenciesOnSelect !== undefined ||\n\t\t\topts.linkCreationEnabled !== undefined ||\n\t\t\topts.progressDragEnabled !== undefined ||\n\t\t\topts.viewportStart !== undefined ||\n\t\t\topts.viewportEnd !== undefined ||\n\t\t\topts.locale !== undefined ||\n\t\t\topts.timelineMinWidth !== undefined;\n\n\t\tconst hasVisualChange = hasLeftPaneChange || hasRightPaneChange || hasLayoutChange;\n\n\t\tif (!hasVisualChange) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\n\t\tif (hasLeftPaneChange && !hasRightPaneChange) {\n\t\t\tthis.#renderGrid();\n\t\t} else if (!hasLeftPaneChange && hasRightPaneChange) {\n\t\t\tthis.#renderTimeline();\n\t\t} else {\n\t\t\tthis.#render();\n\t\t}\n\t}\n\n\t/**\n\t * Programmatically selects or deselects a task.\n\t *\n\t * @param id - The task ID to select, or `null` to clear the selection.\n\t * @param fireCallback - Whether to fire the `onTaskClick` callback. Default `false`.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic select(id: number | null, fireCallback = false): void {\n\t\tthis.#assertAlive();\n\t\tif (id === null) {\n\t\t\tthis.#selectedId = null;\n\t\t} else {\n\t\t\tconst task = this.#input?.tasks.find((t) => t.id === id);\n\t\t\tif (task !== undefined && fireCallback) {\n\t\t\t\tvoid this.#callbacks.onTaskClick?.({task, instance: this});\n\t\t\t}\n\t\t\tthis.#selectedId = id;\n\t\t}\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t}\n\n\t/**\n\t * Collapses all expandable groups in the task tree.\n\t *\n\t * @param fireCallback - Whether to fire the `onExpandCollapseAll` callback. Default `false`.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic collapseAll(fireCallback = false): void {\n\t\tthis.#assertAlive();\n\t\tconst changed = fireCallback ? this.#buildExpandCollapseAllPayload(false) : [];\n\t\tthis.#expandedIds.clear();\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t\tif (changed.length > 0) {\n\t\t\tvoid this.#callbacks.onExpandCollapseAll?.({tasks: changed as unknown as GenTask<TTaskData>[], instance: this});\n\t\t}\n\t}\n\n\t/**\n\t * Expands all expandable groups in the task tree.\n\t *\n\t * @param fireCallback - Whether to fire the `onExpandCollapseAll` callback. Default `false`.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic expandAll(fireCallback = false): void {\n\t\tthis.#assertAlive();\n\t\tconst changed = fireCallback ? this.#buildExpandCollapseAllPayload(true) : [];\n\t\tthis.#expandedIds.clear();\n\t\tif (this.#input !== null) {\n\t\t\tfor (const id of getExpandableTaskIds(this.#input.tasks)) {\n\t\t\t\tthis.#expandedIds.add(id);\n\t\t\t}\n\t\t}\n\t\tif (this.#rafPending && this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t\tthis.#rafId = null;\n\t\t\tthis.#rafPending = false;\n\t\t}\n\t\tthis.#render();\n\t\tif (changed.length > 0) {\n\t\t\tvoid this.#callbacks.onExpandCollapseAll?.({tasks: changed as unknown as GenTask<TTaskData>[], instance: this});\n\t\t}\n\t}\n\n\t#buildExpandCollapseAllPayload(open: boolean): Task[] {\n\t\tif (this.#input === null) {\n\t\t\treturn [];\n\t\t}\n\t\tconst expandableIds = getExpandableTaskIds(this.#input.tasks);\n\t\tconst changed: Task[] = [];\n\t\tfor (const id of expandableIds) {\n\t\t\tconst currentlyExpanded = this.#expandedIds.has(id);\n\t\t\tif (currentlyExpanded !== open) {\n\t\t\t\tconst task = this.#findTask(id);\n\t\t\t\tif (task !== undefined) {\n\t\t\t\t\tchanged.push(task.kind === 'project' ? {...task, open} : {...task});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn changed;\n\t}\n\n\t/**\n\t * Returns the current expand/collapse state of every expandable node\n\t * (project tasks that have children). The result is ordered by the\n\t * input task list order.\n\t *\n\t * @returns An array of `{id, open}` objects for expandable nodes only.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic getOpenStates(): {id: number; open: boolean}[] {\n\t\tthis.#assertAlive();\n\t\tif (this.#input === null) {\n\t\t\treturn [];\n\t\t}\n\t\tconst expandableIds = getExpandableTaskIds(this.#input.tasks);\n\t\tconst result: {id: number; open: boolean}[] = [];\n\t\tfor (const task of this.#input.tasks) {\n\t\t\tif (expandableIds.has(task.id)) {\n\t\t\t\tresult.push({id: task.id, open: this.#expandedIds.has(task.id)});\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes the chart DOM and internal listeners, rendering the instance\n\t * unusable. Subsequent calls to any public method will throw.\n\t */\n\tpublic destroy(): void {\n\t\tif (this.#destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#destroyed = true;\n\t\tthis.#scrollEl.removeEventListener('scroll', this.#onScroll);\n\t\tif (this.#resizeObserver !== null) {\n\t\t\tthis.#resizeObserver.disconnect();\n\t\t} else {\n\t\t\twindow.removeEventListener('resize', this.#applyResponsivePaneStyles);\n\t\t}\n\t\tif (this.#rafId !== null) {\n\t\t\tcancelAnimationFrame(this.#rafId);\n\t\t}\n\t\tthis.#columnResizeCleanup();\n\t\tfor (const {cleanupDrag, cleanupLinkHandles, cleanupProgressDrag, cleanupTooltip} of this.#rightPaneRefs.barRegistry.values()) {\n\t\t\tcleanupDrag?.();\n\t\t\tcleanupLinkHandles?.();\n\t\t\tcleanupProgressDrag?.();\n\t\t\tcleanupTooltip?.();\n\t\t}\n\t\tclearChildren(this.#container);\n\t}\n\n\t#patchTask(id: number, patch: Partial<GanttInput['tasks'][number]>): void {\n\t\tif (this.#input === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst index = this.#taskIndex.get(id);\n\t\tif (index === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tconst target = this.#input.tasks[index];\n\t\tif (target === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#input.tasks[index] = {...target, ...patch} as Task;\n\t}\n\n\t#findTask(id: number): Task | undefined {\n\t\treturn this.#input?.tasks.find((t) => t.id === id);\n\t}\n\n\t#syncActionsColumnVisibility(): void {\n\t\tconst actionsCol = this.#columns.find((c) => c.id === 'actions');\n\t\tif (actionsCol !== undefined) {\n\t\t\tif (this.#showAddTaskButton) {\n\t\t\t\tdelete actionsCol.visible;\n\t\t\t} else {\n\t\t\t\tactionsCol.visible = false;\n\t\t\t}\n\t\t}\n\t}\n\n\treadonly #handleGridClick = (payload: {id: number; task: Task}): void => {\n\t\tconst now = Date.now();\n\t\tconst prev = this.#lastGridClick;\n\t\tif (prev !== null && prev.id === payload.id && now - prev.atMs <= 350) {\n\t\t\tthis.#lastGridClick = null;\n\t\t\tthis.#cbs.onTaskDoubleClick?.({id: payload.id, task: payload.task});\n\t\t\treturn;\n\t\t}\n\t\tthis.#lastGridClick = {id: payload.id, atMs: now};\n\t\tthis.#cbs.onTaskClick?.(payload.id);\n\t};\n\n\treadonly #onScroll = (): void => {\n\t\t({scrollTop: this.#scrollTop} = this.#scrollEl);\n\t\tthis.#scheduleRender();\n\t};\n\n\treadonly #applyResponsivePaneStyles = (): void => {\n\t\tconst computedWidth = computeLeftPaneWidth({\n\t\t\thostWidth: Math.max(0, this.#container.clientWidth),\n\t\t\tdefaultWidth: this.#leftPaneDefaultWidth,\n\t\t\tuserSplitWidth: this.#userSplitWidth,\n\t\t\texplicitOptWidth: this.#opts.leftPaneWidth,\n\t\t\tresponsiveSplitPane: this.#opts.responsiveSplitPane ?? true,\n\t\t\tmobileBreakpoint: this.#opts.mobileBreakpoint ?? MOBILE_BREAKPOINT,\n\t\t\tmobileLeftPaneMinWidth: this.#opts.mobileLeftPaneMinWidth ?? MOBILE_LEFT_PANE_MIN_WIDTH,\n\t\t\tmobileLeftPaneMaxRatio: this.#opts.mobileLeftPaneMaxRatio ?? MOBILE_LEFT_PANE_MAX_RATIO,\n\t\t\ttimelineMinWidth: this.#timelineMinWidth,\n\t\t});\n\t\tthis.#leftPane.style.width = `${computedWidth}px`;\n\t\tthis.#leftPane.style.minWidth = `${computedWidth}px`;\n\t\tthis.#leftPane.style.maxWidth = `${computedWidth}px`;\n\t\tthis.#rightPane.style.minWidth = `${this.#timelineMinWidth}px`;\n\t};\n\n\t#computeState(input: GanttInput): GanttState {\n\t\tconst roots = buildTaskTree(input.tasks);\n\t\tconst allRows = flattenTree(roots, this.#expandedIds);\n\t\tconst [vpStart, vpEnd] =\n\t\t\tthis.#opts.viewportStart !== undefined && this.#opts.viewportEnd !== undefined\n\t\t\t\t? [this.#opts.viewportStart, this.#opts.viewportEnd]\n\t\t\t\t: deriveViewport(allRows, 48);\n\t\tconst weekStartsOn = this.#locale.weekStartsOn ?? 1;\n\t\tconst renderViewportEnd = ceilToScaleBoundary(vpEnd, this.#scale, weekStartsOn);\n\n\t\tconst mapper = createPixelMapper(this.#scale, vpStart);\n\t\tconst totalWidth = Math.ceil(mapper.toX(renderViewportEnd)) + 1;\n\t\tconst layouts = computeLayout(allRows, mapper);\n\t\tconst links = routeLinks(input.links, layouts);\n\n\t\tconst containerH = this.#height - HEADER_H;\n\t\tconst rowCount = allRows.length;\n\t\tconst startIndex = Math.max(0, Math.floor(this.#scrollTop / ROW_HEIGHT) - OVERSCAN);\n\t\tconst endIndex = Math.min(rowCount - 1, Math.ceil((this.#scrollTop + containerH) / ROW_HEIGHT) + OVERSCAN - 1);\n\t\tconst paddingTop = startIndex * ROW_HEIGHT;\n\t\tconst paddingBottom = Math.max(0, (rowCount - 1 - endIndex) * ROW_HEIGHT);\n\n\t\treturn {\n\t\t\tinput,\n\t\t\tscale: this.#scale,\n\t\t\thighlightLinkedDependenciesOnSelect: this.#opts.highlightLinkedDependenciesOnSelect ?? false,\n\t\t\tlinkCreationEnabled: this.#opts.linkCreationEnabled ?? false,\n\t\t\tprogressDragEnabled: this.#opts.progressDragEnabled ?? false,\n\t\t\texpandedIds: this.#expandedIds,\n\t\t\tselectedId: this.#selectedId,\n\t\t\tscrollTop: this.#scrollTop,\n\t\t\tallRows,\n\t\t\tmapper,\n\t\t\tviewportStart: vpStart,\n\t\t\tviewportEnd: renderViewportEnd,\n\t\t\ttotalWidth,\n\t\t\tlayouts,\n\t\t\tlinks,\n\t\t\tstartIndex,\n\t\t\tendIndex,\n\t\t\tpaddingTop,\n\t\t\tpaddingBottom,\n\t\t\tshowWeekends: this.#opts.showWeekends ?? true,\n\t\t\tshowTodayMarker: this.#opts.showTodayMarker ?? true,\n\t\t\tweekendDays: this.#weekendDays,\n\t\t\tspecialDaysByDate: this.#specialDaysByDate,\n\t\t\tlocale: this.#locale,\n\t\t};\n\t}\n\n\treadonly #render = (): void => {\n\t\tthis.#rafPending = false;\n\t\tconst input = this.#input;\n\t\tif (input === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst state = this.#computeState(input);\n\n\t\trenderTimeHeader(this.#rightHeader, state);\n\t\tthis.#renderGridInternal(state);\n\t\trenderRightPane(this.#rightPaneRefs, state, this.#cbs);\n\t};\n\n\treadonly #renderGrid = (): void => {\n\t\tthis.#rafPending = false;\n\t\tconst input = this.#input;\n\t\tif (input === null) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#renderGridInternal(this.#computeState(input));\n\t};\n\n\t#renderGridInternal(state: GanttState): void {\n\t\trenderLeftPane(\n\t\t\tthis.#leftBody,\n\t\t\tstate,\n\t\t\t{\n\t\t\t\tonToggle: (id) => {\n\t\t\t\t\tconst expanded = !this.#expandedIds.has(id);\n\t\t\t\t\tif (expanded) {\n\t\t\t\t\t\tthis.#expandedIds.add(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#expandedIds.delete(id);\n\t\t\t\t\t}\n\t\t\t\t\tconst task = this.#findTask(id);\n\t\t\t\t\tif (task !== undefined) {\n\t\t\t\t\t\tconst payload = task.kind === 'project' ? {...task, open: expanded} : {...task};\n\t\t\t\t\t\tvoid this.#callbacks.onExpandCollapse?.({\n\t\t\t\t\t\t\ttask: payload as unknown as GenTask<TTaskData>,\n\t\t\t\t\t\t\tinstance: this,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tthis.#scheduleRender();\n\t\t\t\t},\n\t\t\t\tonTaskClick: (id) => this.#cbs.onTaskClick?.(id),\n\t\t\t\tonRowClick: (payload) => {\n\t\t\t\t\tthis.#handleGridClick(payload);\n\t\t\t\t},\n\t\t\t\tonTaskDoubleClick: (payload) => this.#cbs.onTaskDoubleClick?.(payload),\n\t\t\t\tonTaskAdd: (id) => this.#cbs.onTaskAdd?.(id),\n\t\t\t},\n\t\t\tthis.#columns,\n\t\t\tthis.#showAddTaskButton,\n\t\t);\n\t}\n\n\treadonly #renderTimeline = (): void => {\n\t\tthis.#rafPending = false;\n\t\tconst input = this.#input;\n\t\tif (input === null) {\n\t\t\treturn;\n\t\t}\n\t\tconst state = this.#computeState(input);\n\n\t\trenderTimeHeader(this.#rightHeader, state);\n\t\trenderRightPane(this.#rightPaneRefs, state, this.#cbs);\n\t};\n\n\t#rebuildLeftPaneHeader(): void {\n\t\tthis.#columnResizeCleanup();\n\t\tclearChildren(this.#leftHeader);\n\t\tconst headerEl = buildLeftPaneHeader(this.#columns, this.#locale);\n\t\tthis.#wireHeaderTreeControls(headerEl);\n\t\tthis.#leftHeader.append(headerEl);\n\t\tthis.#columnResizeCleanup = setupColumnResize(headerEl, this.#leftBody, this.#columns, (updated) => {\n\t\t\tthis.#cbs.onGridColumnsChange?.(updated);\n\t\t});\n\t}\n\n\t#wireHeaderTreeControls(headerEl: HTMLElement): void {\n\t\tconst expandBtn = headerEl.querySelector<HTMLElement>('.gantt-header-expand-btn');\n\t\tconst collapseBtn = headerEl.querySelector<HTMLElement>('.gantt-header-collapse-btn');\n\t\tif (expandBtn !== null) {\n\t\t\texpandBtn.addEventListener('click', (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.expandAll(true);\n\t\t\t});\n\t\t}\n\t\tif (collapseBtn !== null) {\n\t\t\tcollapseBtn.addEventListener('click', (e) => {\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.collapseAll(true);\n\t\t\t});\n\t\t}\n\t}\n\n\t#scheduleRender(): void {\n\t\tif (this.#rafPending || this.#destroyed) {\n\t\t\treturn;\n\t\t}\n\t\tthis.#rafPending = true;\n\t\tthis.#rafId = requestAnimationFrame(this.#render);\n\t}\n\n\t#applyTheme(): void {\n\t\tconst theme = this.#opts.theme ?? 'system';\n\t\tthis.#container.dataset['theme'] = theme;\n\t}\n\n\t#assertAlive(): void {\n\t\tif (this.#destroyed) {\n\t\t\tthrow new GanttError('INSTANCE_DESTROYED', 'Gantt instance was destroyed');\n\t\t}\n\t}\n\n\t#buildDom(): void {\n\t\tconst root = el('div');\n\t\troot.className = 'gantt-root';\n\t\tcss(root, {\n\t\t\theight: `${this.#height}px`,\n\t\t\toverflow: 'hidden',\n\t\t\tdisplay: 'flex',\n\t\t\tflexDirection: 'column',\n\t\t\tfontFamily: 'var(--gantt-font)',\n\t\t\tbackground: 'var(--gantt-bg)',\n\t\t});\n\t\tthis.#root = root;\n\n\t\tconst scrollEl = el('div');\n\t\tcss(scrollEl, {flex: '1', overflow: 'auto', position: 'relative', display: 'flex'});\n\t\troot.append(scrollEl);\n\t\tthis.#scrollEl = scrollEl;\n\n\t\tconst leftPane = el('div');\n\t\tleftPane.dataset['pane'] = 'left';\n\t\tcss(leftPane, {\n\t\t\twidth: `${this.#leftPaneDefaultWidth}px`,\n\t\t\tflexShrink: '0',\n\t\t\tposition: 'sticky',\n\t\t\tleft: '0',\n\t\t\tzIndex: '10',\n\t\t\tbackground: 'var(--gantt-bg)',\n\t\t\tborderRight: '1px solid var(--gantt-border)',\n\t\t});\n\t\tthis.#leftPane = leftPane;\n\n\t\tconst leftHeader = el('div');\n\t\tcss(leftHeader, {position: 'sticky', top: '0', zIndex: '11', background: 'var(--gantt-header-bg)'});\n\t\tconst headerEl = buildLeftPaneHeader(this.#columns, this.#locale);\n\t\tthis.#wireHeaderTreeControls(headerEl);\n\t\tleftHeader.append(headerEl);\n\t\tleftPane.append(leftHeader);\n\t\tthis.#leftHeader = leftHeader;\n\n\t\tconst leftBody = el('div');\n\t\tleftPane.append(leftBody);\n\t\tthis.#leftBody = leftBody;\n\n\t\tthis.#columnResizeCleanup = setupColumnResize(headerEl, leftBody, this.#columns, (updated) => {\n\t\t\tthis.#cbs.onGridColumnsChange?.(updated);\n\t\t});\n\n\t\tscrollEl.append(leftPane);\n\n\t\tconst rightPane = el('div');\n\t\trightPane.dataset['pane'] = 'right';\n\t\tcss(rightPane, {flexShrink: '0', position: 'relative', minWidth: `${this.#timelineMinWidth}px`});\n\t\tthis.#rightPane = rightPane;\n\n\t\tconst rightHeader = el('div');\n\t\tcss(rightHeader, {position: 'sticky', top: '0', zIndex: '9', background: 'var(--gantt-header-bg)'});\n\t\trightPane.append(rightHeader);\n\t\tthis.#rightHeader = rightHeader;\n\n\t\tthis.#rightPaneRefs = createRightPaneRefs();\n\t\trightPane.append(this.#rightPaneRefs.scrollContainer);\n\t\tscrollEl.append(rightPane);\n\n\t\tconst splitterHandle = el('div');\n\t\tsplitterHandle.className = 'gantt-splitter-handle';\n\t\tcss(splitterHandle, {\n\t\t\tposition: 'absolute',\n\t\t\tright: '0',\n\t\t\ttop: '0',\n\t\t\tbottom: '0',\n\t\t\twidth: '4px',\n\t\t\tcursor: 'col-resize',\n\t\t\tzIndex: '20',\n\t\t});\n\t\tleftPane.append(splitterHandle);\n\n\t\tattachSplitter(splitterHandle, leftPane, this.#container, this.#timelineMinWidth, (finalWidth) => {\n\t\t\tthis.#userSplitWidth = finalWidth;\n\t\t\tthis.#cbs.onLeftPaneWidthChange?.(finalWidth);\n\t\t});\n\t}\n\n\t#wireEvents(): void {\n\t\tthis.#rightPaneRefs.absoluteLayer.addEventListener('click', (event) => {\n\t\t\tconst target = event.target as HTMLElement;\n\t\t\tif (target.closest('.gantt-bar, .gantt-milestone, .gantt-resize-handle')) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#selectedId = null;\n\t\t\tthis.#scheduleRender();\n\t\t});\n\n\t\tthis.#root.addEventListener('keydown', (event) => {\n\t\t\tif (event.key === 'Escape' && this.#selectedId !== null) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tthis.#selectedId = null;\n\t\t\t\tthis.#scheduleRender();\n\t\t\t}\n\t\t});\n\n\t\tthis.#scrollEl.addEventListener('scroll', this.#onScroll);\n\t}\n\n\t#setupResizeObserver(): void {\n\t\tif (typeof ResizeObserver !== 'undefined') {\n\t\t\tthis.#resizeObserver = new ResizeObserver(() => {\n\t\t\t\tthis.#applyResponsivePaneStyles();\n\t\t\t});\n\t\t\tthis.#resizeObserver.observe(this.#container);\n\t\t} else {\n\t\t\twindow.addEventListener('resize', this.#applyResponsivePaneStyles);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|