gantt-renderer 0.1.1 → 0.2.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["toTask","MIN_PANE_WIDTH","#container","#opts","#height","#locale","#timelineMinWidth","#columns","#leftPaneDefaultWidth","#weekendDays","#specialDaysByDate","#expandedIds","#cbs","#input","#scale","#taskIndex","#selectedId","#scheduleRender","#patchTask","#buildDom","#wireEvents","#root","#applyTheme","#applyResponsivePaneStyles","#setupResizeObserver","#render","#assertAlive","#rafPending","#rafId","#destroyed","#scrollEl","#onScroll","#resizeObserver","#columnResizeCleanup","#rightPaneRefs","#handleGridClick","#lastGridClick","#scrollTop","#userSplitWidth","#leftPane","#rightPane","#computeState","#rightHeader","#leftBody"],"sources":["../src/gantt-chart/validation/schemas.ts","../src/gantt-chart/errors.ts","../src/gantt-chart/domain/tree.ts","../src/gantt-chart/domain/dependencies.ts","../src/gantt-chart/locale.ts","../src/gantt-chart/domain/dateMath.ts","../src/gantt-chart/timeline/scale.ts","../src/gantt-chart/timeline/pixelMapper.ts","../src/gantt-chart/timeline/layoutEngine.ts","../src/gantt-chart/rendering/linkRouter.ts","../src/gantt-chart/vanilla/dom/helpers.ts","../src/gantt-chart/vanilla/dom/timeHeader.ts","../src/gantt-chart/vanilla/dom/gridColumns.ts","../src/gantt-chart/vanilla/dom/leftPane.ts","../src/gantt-chart/vanilla/dom/dependencyLayer.ts","../src/gantt-chart/vanilla/interaction/drag.ts","../src/gantt-chart/vanilla/interaction/linkCreation.ts","../src/gantt-chart/vanilla/dom/rightPane.ts","../src/gantt-chart/vanilla/utils.ts","../src/gantt-chart/vanilla/splitter.ts","../src/gantt-chart/vanilla/responsive.ts","../src/gantt-chart/vanilla/gantt-chart.ts"],"sourcesContent":["import {z} from 'zod';\n\nexport const LinkTypeSchema = z.enum(['FS', 'SS', 'FF', 'SF']);\nexport const TaskTypeSchema = z.enum(['task', 'project', 'milestone']);\nexport const SpecialDayKindSchema = z.enum(['holiday', 'custom']);\n\nexport const SpecialDaySchema = z.object({\n\t/** ISO date: YYYY-MM-DD */\n\tdate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Expected YYYY-MM-DD'),\n\tkind: SpecialDayKindSchema,\n\tlabel: z.string().min(1).optional(),\n\tclassName: z.string().min(1).optional(),\n});\n\nexport const TaskSchema = z.object({\n\tid: z.number().int().positive(),\n\ttext: z.string().min(1),\n\t/** ISO date: YYYY-MM-DD */\n\tstart_date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Expected YYYY-MM-DD'),\n\t/** Duration in days; 0 = milestone */\n\tduration: z.number().int().min(0),\n\tparent: z.number().int().positive().optional(),\n\t/** 0–1 completion ratio */\n\tprogress: z.number().min(0).max(1).default(0),\n\ttype: TaskTypeSchema.default('task'),\n\t/** Initial expanded state (only relevant for parent nodes) */\n\topen: z.boolean().default(true),\n\tcolor: z.string().optional(),\n});\n\nexport const LinkSchema = z.object({\n\tid: z.number().int().positive(),\n\tsource: z.number().int().positive(),\n\ttarget: z.number().int().positive(),\n\ttype: LinkTypeSchema.default('FS'),\n});\n\nexport const GanttInputSchema = z.object({\n\ttasks: z.array(TaskSchema).min(1),\n\tlinks: z.array(LinkSchema).default([]),\n});\n\nexport type LinkType = z.infer<typeof LinkTypeSchema>;\nexport type TaskType = z.infer<typeof TaskTypeSchema>;\nexport type SpecialDayKind = z.infer<typeof SpecialDayKindSchema>;\nexport type SpecialDay = z.infer<typeof SpecialDaySchema>;\nexport type Task = z.infer<typeof TaskSchema>;\nexport type Link = z.infer<typeof LinkSchema>;\nexport type GanttInput = z.infer<typeof GanttInputSchema>;\n\n/** Parses raw external data. Throws ZodError on failure. */\nexport function parseGanttInput(raw: unknown): GanttInput {\n\treturn GanttInputSchema.parse(raw);\n}\n\n/** Returns null instead of throwing. */\nexport function safeParseGanttInput(raw: unknown): GanttInput | null {\n\tconst result = GanttInputSchema.safeParse(raw);\n\treturn result.success ? result.data : null;\n}\n","export type GanttErrorCode = 'PARENT_REFERENCE' | 'LINK_REFERENCE' | 'DEPENDENCY_CYCLE' | 'INSTANCE_DESTROYED';\n\nexport class GanttError extends Error {\n\tpublic readonly code: GanttErrorCode;\n\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} from '../validation/schemas.ts';\nimport {GanttError} from '../errors.ts';\n\nexport type TaskNode = Task & {\n\tchildren: TaskNode[];\n\t/** 0 = root */\n\tdepth: number;\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 * Throws if any parent reference is unresolvable.\n */\nexport function buildTaskTree(tasks: Task[]): TaskNode[] {\n\tconst map = new Map<number, TaskNode>();\n\tconst roots: TaskNode[] = [];\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: 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 3: 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 */\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/** Returns true when a node has children in the tree. */\nexport function isParent(node: TaskNode): boolean {\n\treturn node.children.length > 0;\n}\n","import {type Link, type 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 * Throws with a human-readable cycle path on detection.\n * Silent return = no cycles.\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 * Returns true when all link source/target ids reference existing tasks.\n * Throws with details on failure.\n */\nexport function validateLinkRefs(tasks: Task[], links: Link[]): void {\n\tconst ids = new Set(tasks.map((t) => t.id));\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\t}\n}\n","export type LocaleLabelKey =\n\t| 'aria_task'\n\t| 'aria_milestone'\n\t| 'add_subtask_title'\n\t| 'column_task_name'\n\t| 'column_start_time'\n\t| 'column_duration'\n\t| 'column_quarter';\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\nexport const EN_US_LABELS: Record<LocaleLabelKey, string> = {\n\taria_task: 'Task {0}',\n\taria_milestone: 'Milestone {0}',\n\tadd_subtask_title: 'Add subtask',\n\tcolumn_task_name: 'Task name',\n\tcolumn_start_time: 'Start time',\n\tcolumn_duration: 'Duration',\n\tcolumn_quarter: 'Q',\n};\n\nexport const CHART_LOCALE_EN_US: ChartLocale = {\n\tcode: 'en-US',\n\tlabels: EN_US_LABELS,\n\tweekStartsOn: 0,\n\tweekNumbering: 'iso',\n\tweekendDays: [0, 6],\n};\n\n/**\n * Resolves a 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 */\nexport function resolveChartLocale(raw: ChartLocale | string | undefined): ChartLocale {\n\tif (raw === undefined) {\n\t\treturn CHART_LOCALE_EN_US;\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\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype IntlLocaleWithWeekInfo = Intl.Locale & {getWeekInfo?: () => {firstDay: number; weekend: number[]; minimalDays: number}};\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 */\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\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\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 */\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\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\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 */\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\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\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 */\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\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 label template by replacing `{0}` with the given argument.\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/** Parses YYYY-MM-DD → UTC midnight Date. Throws on invalid input. */\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/** Returns date + n days (exact ms arithmetic). */\nexport function addDays(date: Date, days: number): Date {\n\treturn new Date(date.getTime() + days * 86_400_000);\n}\n\n/** Difference in days (float). Positive when b > a. */\nexport function diffDays(a: Date, b: Date): number {\n\treturn (b.getTime() - a.getTime()) / 86_400_000;\n}\n\n/** UTC start-of-day. */\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 * Defaults to Monday when locale is omitted.\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/** UTC start-of-month. */\nexport function startOfMonth(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));\n}\n\n/** UTC start-of-quarter. */\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/** UTC start-of-year. */\nexport function startOfYear(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), 0, 1));\n}\n\n/** UTC start-of-hour. */\nexport function startOfHour(date: Date): Date {\n\treturn new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()));\n}\n\n/**\n * Formats a Date for the time-header label given the active scale.\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.\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\nfunction resolveQuarterLabel(locale: ChartLocale): string {\n\tif (locale.labels?.column_quarter !== undefined) {\n\t\treturn locale.labels.column_quarter;\n\t}\n\treturn EN_US_LABELS.column_quarter;\n}\n\n/** Formats YYYY-MM-DD for display in the grid. */\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 * Defaults to Monday (1) when omitted.\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 */\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","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\tdurationToWidth: (days: number) => number;\n\t/** Pixel width → days (float) */\n\twidthToDuration: (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 */\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\tdurationToWidth(days: number): number {\n\t\t\treturn days * msPerDay * pxPerMs;\n\t\t},\n\t\twidthToDuration(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, addDays} 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\ttype: '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 */\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.start_date);\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\tconst type = task.type ?? 'task';\n\n\t\tif (type === '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\ttype: '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 width = Math.max(mapper.durationToWidth(task.duration), 4);\n\t\tconst progressWidth = width * Math.min(1, Math.max(0, task.progress ?? 0));\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\ttype,\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 */\nexport function totalContentHeight(rowCount: number): number {\n\treturn rowCount * ROW_HEIGHT;\n}\n\n/**\n * Derives viewport bounds from task data with padding.\n * Returns [start, end] as UTC midnight dates.\n */\nexport function deriveViewport(tasks: TaskNode[], paddingDays = 2): [Date, Date] {\n\tif (tasks.length === 0) {\n\t\tconst now = new Date();\n\t\treturn [now, addDays(now, 30)];\n\t}\n\n\tlet minMs = Infinity;\n\tlet maxMs = -Infinity;\n\n\tfor (const task of tasks) {\n\t\tconst start = parseDate(task.start_date);\n\t\tconst end = addDays(start, task.duration);\n\t\tif (start.getTime() < minMs) {\n\t\t\tminMs = start.getTime();\n\t\t}\n\t\tif (end.getTime() > maxMs) {\n\t\t\tmaxMs = end.getTime();\n\t\t}\n\t}\n\n\treturn [addDays(new Date(minMs), -paddingDays), addDays(new Date(maxMs), paddingDays)];\n}\n","import {type Link} from '../validation/schemas.ts';\nimport {type BarLayout} from '../timeline/layoutEngine.ts';\nimport {MILESTONE_HALF} 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\t/** Ordered vertices of the orthogonal polyline (source → target). */\n\tpoints: Point[];\n};\n\nconst TURN_MARGIN = 12; // px gap before/after bar for routing clearance\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 */\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\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\n/**\n * Produces the vertex list for an orthogonal connector between src and tgt.\n *\n * Link semantics:\n * FS = source.finish → target.start (most common)\n * SS = source.start → target.start\n * FF = source.finish → target.finish\n * SF = source.start → target.finish\n */\nfunction route(type: Link['type'], src: BarLayout, tgt: BarLayout): Point[] {\n\tlet sx: number, tx: number;\n\tconst sy = src.centerY;\n\tconst ty = tgt.centerY;\n\n\tswitch (type) {\n\t\tcase 'FS': {\n\t\t\tsx = src.type === 'milestone' ? src.x + MILESTONE_HALF : src.x + src.width;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x - MILESTONE_HALF : tgt.x;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'SS': {\n\t\t\tsx = src.type === 'milestone' ? src.x - MILESTONE_HALF : src.x;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x - MILESTONE_HALF : tgt.x;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'FF': {\n\t\t\tsx = src.type === 'milestone' ? src.x + MILESTONE_HALF : src.x + src.width;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x + MILESTONE_HALF : tgt.x + tgt.width;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'SF': {\n\t\t\tsx = src.type === 'milestone' ? src.x - MILESTONE_HALF : src.x;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x + MILESTONE_HALF : tgt.x + tgt.width;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Same row: direct horizontal\n\tif (Math.abs(sy - ty) < 1) {\n\t\treturn [\n\t\t\t{x: sx, y: sy},\n\t\t\t{x: tx, y: ty},\n\t\t];\n\t}\n\n\t// Forward path: midpoint between sx and tx\n\tif (sx <= tx) {\n\t\tconst midX = sx + Math.max(TURN_MARGIN, (tx - sx) / 2);\n\t\treturn [\n\t\t\t{x: sx, y: sy},\n\t\t\t{x: midX, y: sy},\n\t\t\t{x: midX, y: ty},\n\t\t\t{x: tx, y: ty},\n\t\t];\n\t}\n\n\t// Backward path: loop around via margins\n\tconst loopX = tx - TURN_MARGIN;\n\treturn [\n\t\t{x: sx, y: sy},\n\t\t{x: sx + TURN_MARGIN, y: sy},\n\t\t{x: sx + TURN_MARGIN, y: (sy + ty) / 2},\n\t\t{x: loopX, y: (sy + ty) / 2},\n\t\t{x: loopX, y: ty},\n\t\t{x: tx, y: ty},\n\t];\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/** Batches style assignments; avoids repeated style recalculations. */\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/** Removes all child nodes from elem. Faster than innerHTML = '' for large subtrees. */\nexport function clearChildren(elem: Element): void {\n\twhile (elem.firstChild !== null) {\n\t\telem.removeChild(elem.firstChild);\n\t}\n}\n\n/** Appends all nodes from an array/fragment into parent in one pass. */\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/** Creates an SVG element in the SVG namespace. */\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/** Sets multiple SVG attributes in one call. */\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} from '../state.ts';\nimport {nextScaleBoundary, snapToScaleBoundary} from '../../timeline/scale.ts';\nimport {formatHeaderLabel, formatUpperLabel} from '../../domain/dateMath.ts';\n\ntype Cell = {label: string; x: number; width: number};\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 */\nexport function renderTimeHeader(container: HTMLElement, state: GanttState): void {\n\tconst {scale, viewportStart, viewportEnd, mapper, totalWidth, locale} = state;\n\tconst weekStartsOn = locale.weekStartsOn ?? 1;\n\n\tconst upperCells: Cell[] = [];\n\tconst lowerCells: Cell[] = [];\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});\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\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\n/** Inline style helper local to this module. */\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","import {formatDisplayDate} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS} from '../../locale.ts';\nimport {type Task} from '../../validation/schemas.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\n\nexport type GridColumn = {\n\tid: string;\n\theader: string;\n\twidth: string;\n\talign?: 'left' | 'center' | 'right';\n\tvisible?: boolean;\n\tfield?: keyof Task;\n\tformat?: (value: unknown, task: Task, 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: 'start_date',\n\t\theader: 'Start time',\n\t\twidth: '90px',\n\t\tfield: 'start_date',\n\t\tformat: (value, _task, _row, locale) => formatDisplayDate(String(value), locale),\n\t},\n\t{\n\t\tid: 'duration',\n\t\theader: 'Duration',\n\t\twidth: '68px',\n\t\tfield: 'duration',\n\t\tformat: (value) => ((value as number) > 0 ? String(value) : '—'),\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 */\nexport function gridColumnDefaults(locale: ChartLocale): GridColumn[] {\n\treturn [\n\t\t{\n\t\t\tid: 'name',\n\t\t\theader: locale.labels?.column_task_name ?? EN_US_LABELS.column_task_name,\n\t\t\twidth: '1fr',\n\t\t},\n\t\t{\n\t\t\tid: 'start_date',\n\t\t\theader: locale.labels?.column_start_time ?? EN_US_LABELS.column_start_time,\n\t\t\twidth: '90px',\n\t\t\tfield: 'start_date',\n\t\t\tformat: (value, _task, _row, loc) => formatDisplayDate(String(value), loc),\n\t\t},\n\t\t{\n\t\t\tid: 'duration',\n\t\t\theader: locale.labels?.column_duration ?? EN_US_LABELS.column_duration,\n\t\t\twidth: '68px',\n\t\t\tfield: 'duration',\n\t\t\tformat: (value) => ((value as number) > 0 ? String(value) : '—'),\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\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\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$/;\nconst FR_RE = /^(\\d+(?:\\.\\d+)?)fr$/;\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\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 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\tonSelect: (id: number) => void;\n\tonRowClick: (payload: {id: number; task: Task}) => void;\n\tonTaskEditIntent: (payload: {id: number; source: 'grid'; trigger: 'double_click'; task: Task}) => void;\n\tonAdd: (id: number) => void;\n};\n\n/** Renders the left grid pane. */\nexport function renderLeftPane(container: HTMLElement, state: GanttState, cbs: LeftPaneCallbacks, columns: GridColumn[]): 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));\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\nfunction buildRow(\n\trow: TaskNode,\n\tselectedId: number | null,\n\texpandedIds: Set<number>,\n\tcbs: LeftPaneCallbacks,\n\tcolumns: GridColumn[],\n\tlocale: ChartLocale,\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.onSelect(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));\n\t}\n\n\treturn wrapper;\n}\n\nfunction buildCell(column: GridColumn, row: TaskNode, expandedIds: Set<number>, cbs: LeftPaneCallbacks, locale: ChartLocale): 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 buildAddButton(row, cbs, locale);\n\t\t}\n\t\tdefault: {\n\t\t\treturn buildDataCell(row, column, locale);\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 ? '▾' : '▸';\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.type === '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 = 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 = rawValue !== null && rawValue !== undefined ? String(rawValue) : '';\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?.add_subtask_title ?? EN_US_LABELS.add_subtask_title;\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.onAdd(row.id);\n\t});\n\n\treturn btn;\n}\n\nfunction toTask(row: TaskNode): Task {\n\treturn {\n\t\tid: row.id,\n\t\ttext: row.text,\n\t\tstart_date: row.start_date,\n\t\tduration: row.duration,\n\t\tprogress: row.progress,\n\t\ttype: row.type,\n\t\topen: row.open,\n\t\t...(row.parent === undefined ? {} : {parent: row.parent}),\n\t\t...(row.color === undefined ? {} : {color: row.color}),\n\t};\n}\n\n/** Builds the header row for the left pane. */\nexport function buildLeftPaneHeader(columns: GridColumn[]): 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\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 * Returns a cleanup function.\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_SIZE = 6;\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 */\nexport function createDependencyLayer(totalWidth: number, totalHeight: number): SVGSVGElement {\n\tconst svg = document.createElementNS(NS, 'svg');\n\tsetAttrs(svg, {\n\t\twidth: totalWidth,\n\t\theight: totalHeight,\n\t});\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: '9',\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: 'M 0 1 L 10 5 L 0 9 Z', 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 * Pass valid=true when the pointer is over a valid target bar.\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\t'stroke-dasharray': valid ? 'none' : '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 */\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 */\nexport function updateDependencyLayer(\n\tsvg: SVGSVGElement,\n\tlinks: RoutedLink[],\n\ttotalWidth: number,\n\ttotalHeight: number,\n\tselectedTaskId: number | null,\n\thighlightLinkedDependenciesOnSelect: boolean,\n): void {\n\tsetAttrs(svg, {width: totalWidth, height: totalHeight});\n\n\t// Remove existing paths (keep defs at index 0, and keep ghost path)\n\tconst toRemove: Element[] = [];\n\tfor (let i = 1; i < svg.children.length; i++) {\n\t\tconst child = svg.children[i];\n\t\tif (child !== undefined && !child.classList.contains('gantt-ghost-line')) {\n\t\t\ttoRemove.push(child);\n\t\t}\n\t}\n\tfor (const node of toRemove) {\n\t\tsvg.removeChild(node);\n\t}\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\tlet d = `M ${points[0]?.x ?? 0},${points[0]?.y ?? 0}`;\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst p = points[i];\n\t\t\tif (p !== undefined) {\n\t\t\t\td += ` L ${p.x},${p.y}`;\n\t\t\t}\n\t\t}\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});\n\t\tsvg.append(path);\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 Task} from '../../validation/schemas.ts';\nimport {type GanttCallbacks} from '../gantt-chart.ts';\n\n/**\n * Attaches drag-to-move and resize listeners to a bar element.\n * Returns a cleanup function that removes all listeners.\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 */\nexport function attachDrag(barEl: HTMLElement, resizeHandleEl: HTMLElement, task: TaskNode, getMapper: () => PixelMapper, cbs: GanttCallbacks): () => void {\n\t// ── Move ───────────────────────────────────────────────────────────────\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.onSelect?.(task.id);\n\n\t\tconst startX = e.clientX;\n\t\tconst originDate = parseDate(task.start_date);\n\t\tconst mapper = getMapper(); // snapshot at mousedown\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst days = Math.round(mapper.widthToDuration(dx));\n\t\t\tcbs.onMove?.({id: task.id, startDate: addDays(originDate, days)});\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}\n\n\t\tbarEl.style.cursor = 'grabbing';\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\t// ── Resize ─────────────────────────────────────────────────────────────\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\tconst origDur = task.duration;\n\t\tconst mapper = getMapper();\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst daysDelta = Math.round(mapper.widthToDuration(dx));\n\t\t\tcbs.onResize?.({id: task.id, duration: Math.max(1, origDur + daysDelta)});\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}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tfunction onBarClick(event: MouseEvent): void {\n\t\tif (event.detail !== 2) {\n\t\t\treturn;\n\t\t}\n\t\tcbs.onTaskEditIntent?.({id: task.id, source: 'bar', trigger: 'double_click', task: toTask(task)});\n\t}\n\n\tbarEl.addEventListener('pointerdown', onBarDown);\n\tbarEl.addEventListener('click', onBarClick);\n\tresizeHandleEl.addEventListener('pointerdown', onResizeDown);\n\n\treturn () => {\n\t\tbarEl.removeEventListener('pointerdown', onBarDown);\n\t\tbarEl.removeEventListener('click', onBarClick);\n\t\tresizeHandleEl.removeEventListener('pointerdown', onResizeDown);\n\t};\n}\n\n/**\n * Attaches click-to-select on a milestone diamond.\n * Returns cleanup.\n */\nexport function attachMilestoneClick(diamondEl: HTMLElement, taskId: number, cbs: GanttCallbacks): () => void {\n\tfunction onClick(): void {\n\t\tcbs.onSelect?.(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.onTaskEditIntent?.({id: taskId, source: 'milestone', trigger: 'double_click', 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\nfunction toTask(row: TaskNode): Task {\n\treturn {\n\t\tid: row.id,\n\t\ttext: row.text,\n\t\tstart_date: row.start_date,\n\t\tduration: row.duration,\n\t\tprogress: row.progress,\n\t\ttype: row.type,\n\t\topen: row.open,\n\t\t...(row.parent === undefined ? {} : {parent: row.parent}),\n\t\t...(row.color === undefined ? {} : {color: row.color}),\n\t};\n}\n","import {type GanttCallbacks} from '../gantt-chart.ts';\nimport {showGhostLine, hideGhostLine} from '../dom/dependencyLayer.ts';\n\n/**\n * Attaches a link-creation drag listener to an endpoint handle.\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: GanttCallbacks,\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 */\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} 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 {type GanttCallbacks} from '../gantt-chart.ts';\nimport {startOfDay} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS, formatLabel} from '../../locale.ts';\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\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}\n\t>;\n};\n\n/** Creates the skeleton DOM structure for the right pane. Call once. */\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: '0', left: '0'});\n\n\tscrollContainer.append(stripeContainer);\n\tscrollContainer.append(absoluteLayer);\n\tabsoluteLayer.append(svgLayer);\n\n\treturn {\n\t\tscrollContainer,\n\t\tstripeContainer,\n\t\tabsoluteLayer,\n\t\tsvgLayer,\n\t\tbarRegistry: new Map(),\n\t};\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 */\nexport function renderRightPane(refs: RightPaneRefs, state: GanttState, cbs: GanttCallbacks): 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} of barRegistry.values()) {\n\t\tcleanupDrag();\n\t\tcleanupLinkHandles?.();\n\t}\n\tbarRegistry.clear();\n\n\t// Grid lines\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 within timeline bounds)\n\tconst todayX = mapper.toX(new Date());\n\tconst todayLineWidth = 2;\n\tif (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.type === 'milestone') {\n\t\t\trenderMilestone(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, cbs, state);\n\t\t} else {\n\t\t\trenderBar(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, state, cbs);\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);\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: GanttCallbacks,\n): void {\n\tconst selected = task.id === selectedId;\n\tconst color = BAR_COLOR[layout.type] ?? 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.type === 'project' ? '3px' : '4px',\n\t\tcursor: '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\tif (layout.progressWidth > 0) {\n\t\tconst prog = el('div');\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\tpointerEvents: 'none',\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, 'aria_task', task.text));\n\tbar.setAttribute('aria-pressed', String(selected));\n\tbar.dataset['taskId'] = String(task.id);\n\tbar.addEventListener('click', () => {\n\t\tcbs.onSelect?.(task.id);\n\t});\n\tbar.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onSelect?.(task.id);\n\t\t}\n\t});\n\n\t// Resize handle\n\tconst handle = el('div');\n\thandle.className = 'gantt-resize-handle';\n\tcss(handle, {\n\t\tposition: 'absolute',\n\t\tright: '0',\n\t\ttop: '0',\n\t\twidth: '8px',\n\t\theight: '100%',\n\t\tcursor: 'ew-resize',\n\t\tzIndex: '1',\n\t\ttouchAction: 'none',\n\t});\n\tbar.append(handle);\n\n\tlayer.insertBefore(bar, svgLayer);\n\n\tconst cleanupDrag = attachDrag(bar, handle, task, () => state.mapper, cbs);\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\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t} = {bar, resizeHandle: handle, cleanupDrag};\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\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: GanttCallbacks,\n\tstate: GanttState,\n): void {\n\tconst selected = task.id === selectedId;\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: 'pointer',\n\t\tzIndex: '4',\n\t});\n\tdiamond.tabIndex = 0;\n\tdiamond.setAttribute('role', 'button');\n\tdiamond.setAttribute('aria-label', ariaLabel(state.locale, 'aria_milestone', 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.onSelect?.(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\tconst cleanupDrag = attachMilestoneClick(diamond, task.id, cbs);\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\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t} = {bar: diamond, resizeHandle: dummy, cleanupDrag};\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\n\t}\n\tregistry.set(task.id, entry);\n}\n\nfunction ariaLabel(locale: ChartLocale, key: 'aria_task' | 'aria_milestone', arg: string): string {\n\tconst template = locale.labels?.[key] ?? EN_US_LABELS[key];\n\treturn formatLabel(template, arg);\n}\n","import {SpecialDaySchema, type 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 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 toIsoDate(date: Date): string {\n\treturn date.toISOString().slice(0, 10);\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.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 {type GanttInput, type SpecialDay, type Task} 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 {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 {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\nexport type OnTaskSelect = (taskId: number | null) => void;\nexport type OnTaskMove = (payload: {id: number; startDate: Date}) => void;\nexport type OnTaskResize = (payload: {id: number; duration: number}) => void;\nexport type OnTaskAdd = (payload: {parentId: number}) => void;\nexport type OnTaskDoubleClick = (payload: {id: number; source: 'grid' | 'bar' | 'milestone'}) => void;\nexport type OnTaskEditIntent = (payload: {id: number; source: 'grid' | 'bar' | 'milestone'; trigger: 'double_click'; task: Task}) => void;\nexport type OnLinkCreate = (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n\nexport type GanttCallbacks = {\n\tonSelect?: OnTaskSelect;\n\tonMove?: OnTaskMove;\n\tonResize?: OnTaskResize;\n\tonAdd?: OnTaskAdd;\n\tonTaskDoubleClick?: OnTaskDoubleClick;\n\tonTaskEditIntent?: OnTaskEditIntent;\n\tonLinkCreate?: OnLinkCreate;\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\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} & GanttCallbacks;\n\nexport type GanttInstance = {\n\tupdate: (input: GanttInput) => void;\n\tsetScale: (scale: TimeScale) => void;\n\tselect: (id: number | null) => void;\n\tcollapseAll: () => void;\n\texpandAll: () => void;\n\tdestroy: () => void;\n};\n\nconst HEADER_H = 52;\nconst OVERSCAN = 4;\nexport class GanttChart implements GanttInstance {\n\treadonly #container: HTMLElement;\n\treadonly #opts: GanttOptions;\n\t#input: GanttInput;\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\t#taskIndex: Map<number, number>;\n\t#lastGridClick: {id: number; atMs: number} | null = null;\n\t#userSplitWidth: number | null = null;\n\n\treadonly #height: number;\n\treadonly #locale: ChartLocale;\n\treadonly #timelineMinWidth: number;\n\treadonly #columns: GridColumn[];\n\treadonly #leftPaneDefaultWidth: number;\n\treadonly #weekendDays: Set<number>;\n\treadonly #specialDaysByDate: Map<string, ResolvedSpecialDay>;\n\treadonly #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#leftBody!: HTMLElement;\n\t#rightPane!: HTMLElement;\n\t#rightHeader!: HTMLElement;\n\t#rightPaneRefs!: RightPaneRefs;\n\treadonly #cbs: GanttCallbacks;\n\n\t#resizeObserver: ResizeObserver | null = null;\n\t#columnResizeCleanup!: () => void;\n\n\tpublic constructor(container: HTMLElement, input: GanttInput, opts: GanttOptions = {}) {\n\t\tthis.#container = container;\n\n\t\tvalidateLinkRefs(input.tasks, input.links);\n\t\tdetectCycles(input.tasks, input.links);\n\n\t\tthis.#input = input;\n\t\tthis.#scale = opts.scale ?? 'day';\n\t\tthis.#opts = opts;\n\t\tthis.#taskIndex = buildTaskIndex(input.tasks);\n\t\tthis.#locale = resolveChartLocale(opts.locale);\n\t\tthis.#columns = opts.gridColumns ?? gridColumnDefaults(this.#locale);\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 = getInitialExpandedIds(input.tasks);\n\n\t\tthis.#cbs = {\n\t\t\tonSelect: (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\topts.onSelect?.(this.#selectedId);\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonTaskDoubleClick: (payload): void => {\n\t\t\t\topts.onTaskDoubleClick?.(payload);\n\t\t\t},\n\t\t\tonTaskEditIntent: (payload): void => {\n\t\t\t\topts.onTaskEditIntent?.(payload);\n\t\t\t\topts.onTaskDoubleClick?.({id: payload.id, source: payload.source});\n\t\t\t},\n\t\t\tonMove: (payload): void => {\n\t\t\t\tconst iso = payload.startDate.toISOString().slice(0, 10);\n\t\t\t\tthis.#patchTask(payload.id, {start_date: iso});\n\t\t\t\topts.onMove?.(payload);\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonResize: (payload): void => {\n\t\t\t\tthis.#patchTask(payload.id, {duration: payload.duration});\n\t\t\t\topts.onResize?.(payload);\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonLeftPaneWidthChange: (width): void => {\n\t\t\t\topts.onLeftPaneWidthChange?.(width);\n\t\t\t},\n\t\t\tonGridColumnsChange: (updatedColumns): void => {\n\t\t\t\topts.onGridColumnsChange?.(updatedColumns);\n\t\t\t},\n\t\t\tonLinkCreate: (payload): void => {\n\t\t\t\topts.onLinkCreate?.(payload);\n\t\t\t},\n\t\t};\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\n\t\tthis.#render();\n\t}\n\n\tpublic update(newInput: GanttInput): void {\n\t\tthis.#assertAlive();\n\t\tvalidateLinkRefs(newInput.tasks, newInput.links);\n\t\tdetectCycles(newInput.tasks, newInput.links);\n\t\tthis.#input = newInput;\n\t\tthis.#taskIndex = buildTaskIndex(newInput.tasks);\n\t\tthis.#scheduleRender();\n\t}\n\n\tpublic setScale(scale: TimeScale): void {\n\t\tthis.#assertAlive();\n\t\tthis.#scale = scale;\n\t\tthis.#scheduleRender();\n\t}\n\n\tpublic select(id: number | null): void {\n\t\tthis.#assertAlive();\n\t\tthis.#selectedId = id;\n\t\tthis.#opts.onSelect?.(id);\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\tpublic collapseAll(): void {\n\t\tthis.#assertAlive();\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}\n\n\tpublic expandAll(): void {\n\t\tthis.#assertAlive();\n\t\tthis.#expandedIds.clear();\n\t\tfor (const id of getExpandableTaskIds(this.#input.tasks)) {\n\t\t\tthis.#expandedIds.add(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\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} of this.#rightPaneRefs.barRegistry.values()) {\n\t\t\tcleanupDrag();\n\t\t\tcleanupLinkHandles?.();\n\t\t}\n\t\tclearChildren(this.#container);\n\t}\n\n\t#patchTask(id: number, patch: Partial<GanttInput['tasks'][number]>): void {\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};\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.onTaskEditIntent?.({id: payload.id, source: 'grid', trigger: 'double_click', task: payload.task});\n\t\t\treturn;\n\t\t}\n\t\tthis.#lastGridClick = {id: payload.id, atMs: now};\n\t\tthis.#cbs.onSelect?.(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(): GanttState {\n\t\tconst roots = buildTaskTree(this.#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, 2);\n\n\t\tconst mapper = createPixelMapper(this.#scale, vpStart);\n\t\tconst totalWidth = Math.ceil(mapper.toX(vpEnd)) + 1;\n\t\tconst layouts = computeLayout(allRows, mapper);\n\t\tconst links = routeLinks(this.#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: this.#input,\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\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: vpEnd,\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\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 state = this.#computeState();\n\n\t\trenderTimeHeader(this.#rightHeader, state);\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\tif (this.#expandedIds.has(id)) {\n\t\t\t\t\t\tthis.#expandedIds.delete(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#expandedIds.add(id);\n\t\t\t\t\t}\n\t\t\t\t\tthis.#scheduleRender();\n\t\t\t\t},\n\t\t\t\tonSelect: (id) => this.#cbs.onSelect?.(id),\n\t\t\t\tonRowClick: (payload) => {\n\t\t\t\t\tthis.#handleGridClick(payload);\n\t\t\t\t},\n\t\t\t\tonTaskEditIntent: (payload) => this.#cbs.onTaskEditIntent?.(payload),\n\t\t\t\tonAdd: (id) => this.#cbs.onAdd?.({parentId: id}),\n\t\t\t},\n\t\t\tthis.#columns,\n\t\t);\n\t\trenderRightPane(this.#rightPaneRefs, state, this.#cbs);\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);\n\t\tleftHeader.append(headerEl);\n\t\tleftPane.append(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.#cbs.onSelect?.(null);\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.#cbs.onSelect?.(null);\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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"}
1
+ {"version":3,"file":"index.mjs","names":["toTask","MIN_PANE_WIDTH","#container","#opts","#height","#locale","#timelineMinWidth","#columns","#leftPaneDefaultWidth","#weekendDays","#specialDaysByDate","#cbs","#scale","#taskIndex","#expandedIds","#selectedId","#scheduleRender","#patchTask","#buildDom","#wireEvents","#root","#applyTheme","#applyResponsivePaneStyles","#setupResizeObserver","#assertAlive","#input","#rafPending","#rafId","#render","#destroyed","#scrollEl","#onScroll","#resizeObserver","#columnResizeCleanup","#rightPaneRefs","#handleGridClick","#lastGridClick","#scrollTop","#userSplitWidth","#leftPane","#rightPane","#computeState","#rightHeader","#leftBody"],"sources":["../src/gantt-chart/validation/schemas.ts","../src/gantt-chart/errors.ts","../src/gantt-chart/domain/tree.ts","../src/gantt-chart/domain/dependencies.ts","../src/gantt-chart/locale.ts","../src/gantt-chart/domain/dateMath.ts","../src/gantt-chart/timeline/scale.ts","../src/gantt-chart/timeline/pixelMapper.ts","../src/gantt-chart/timeline/layoutEngine.ts","../src/gantt-chart/rendering/linkRouter.ts","../src/gantt-chart/vanilla/dom/helpers.ts","../src/gantt-chart/vanilla/dom/timeHeader.ts","../src/gantt-chart/vanilla/dom/gridColumns.ts","../src/gantt-chart/vanilla/dom/leftPane.ts","../src/gantt-chart/vanilla/dom/dependencyLayer.ts","../src/gantt-chart/vanilla/interaction/drag.ts","../src/gantt-chart/vanilla/interaction/linkCreation.ts","../src/gantt-chart/vanilla/dom/rightPane.ts","../src/gantt-chart/vanilla/utils.ts","../src/gantt-chart/vanilla/splitter.ts","../src/gantt-chart/vanilla/responsive.ts","../src/gantt-chart/vanilla/gantt-chart.ts"],"sourcesContent":["import {z} from 'zod';\n\nexport const LinkTypeSchema = z.enum(['FS', 'SS', 'FF', 'SF']);\nexport const TaskTypeSchema = z.enum(['task', 'project', 'milestone']);\nexport const SpecialDayKindSchema = z.enum(['holiday', 'custom']);\n\nexport const SpecialDaySchema = z.object({\n\t/** ISO date: YYYY-MM-DD */\n\tdate: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Expected YYYY-MM-DD'),\n\tkind: SpecialDayKindSchema,\n\tlabel: z.string().min(1).optional(),\n\tclassName: z.string().min(1).optional(),\n});\n\nexport const TaskSchema = z.object({\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}$/, 'Expected YYYY-MM-DD'),\n\t/** Duration in hours; 0 = milestone */\n\tdurationHours: z.number().int().min(0),\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/** 0–100 completion percentage (integer) */\n\tpercentComplete: z.number().int().min(0).max(100).default(0),\n\t/**\n\t * Task type: `'task'`, `'project'`, or `'milestone'`.\n\t *\n\t * - `'task'` — A regular task with a colored bar.\n\t * - `'project'` — A summary/group row with a colored bar.\n\t * - `'milestone'` — A zero-duration marker rendered as a diamond.\n\t *\n\t * @default 'task'\n\t */\n\ttype: TaskTypeSchema.default('task'),\n\t/**\n\t * Initial expanded state for tree hierarchy.\n\t * When `false`, children of this task are hidden on initial render.\n\t * Only relevant for tasks with child tasks.\n\t *\n\t * @default true\n\t */\n\topen: z.boolean().default(true),\n\t/** Optional CSS color value for the task bar. Overrides the default color assignment. */\n\tcolor: z.string().optional(),\n});\n\nexport const LinkSchema = z.object({\n\t/** Unique positive integer identifier for the dependency link. */\n\tid: z.number().int().positive(),\n\t/** The `id` of the predecessor task (the task that drives the dependency). */\n\tsource: z.number().int().positive(),\n\t/** The `id` of the successor task (the task that depends on the predecessor). */\n\ttarget: z.number().int().positive(),\n\t/**\n\t * Dependency type.\n\t *\n\t * - `'FS'` — Finish-to-start: successor starts after predecessor finishes.\n\t * - `'SS'` — Start-to-start: successor starts at the same time as predecessor.\n\t * - `'FF'` — Finish-to-finish: successor finishes at the same time as predecessor.\n\t * - `'SF'` — Start-to-finish: successor finishes after predecessor starts.\n\t *\n\t * @default 'FS'\n\t */\n\ttype: LinkTypeSchema.default('FS'),\n});\n\nexport const GanttInputSchema = z.object({\n\t/** Array of task objects. At least one task is required. */\n\ttasks: z.array(TaskSchema).min(1),\n\t/** Optional array of dependency link objects. Defaults to empty array. */\n\tlinks: z.array(LinkSchema).default([]),\n});\n\n/** The raw, unvalidated input shape that consumers pass to {@link parseGanttInput}. */\nexport type GanttInputRaw = z.input<typeof GanttInputSchema>;\n/** Allowed dependency link type values: `'FS'`, `'SS'`, `'FF'`, or `'SF'`. */\nexport type LinkType = z.infer<typeof LinkTypeSchema>;\n/** Allowed task type values: `'task'`, `'project'`, or `'milestone'`. */\nexport type TaskType = z.infer<typeof TaskTypeSchema>;\nexport type SpecialDayKind = z.infer<typeof SpecialDayKindSchema>;\nexport type SpecialDay = z.infer<typeof SpecialDaySchema>;\n/**\n * A project task in the Gantt chart. Defines timing (start date, duration in hours),\n * hierarchy (parent id), and visual properties (type, percentComplete, color).\n */\nexport type Task = z.infer<typeof TaskSchema>;\n/**\n * A dependency link between two tasks. The `type` determines the scheduling constraint\n * (e.g., finish-to-start, start-to-start).\n */\nexport type Link = z.infer<typeof LinkSchema>;\n/**\n * The complete input data for the chart.\n *\n * Pass a raw plain object (typed as {@link GanttInputRaw}) to\n * {@link parseGanttInput} to validate and get back a typed {@link GanttInput}.\n */\nexport type GanttInput = z.infer<typeof GanttInputSchema>;\n\n/**\n * Parses raw external data.\n *\n * @param raw - The unvalidated input from the consumer.\n * @returns The parsed and validated {@link GanttInput}.\n * @throws {import('zod').ZodError} On schema validation failure.\n */\nexport function parseGanttInput(raw: GanttInputRaw): GanttInput {\n\treturn GanttInputSchema.parse(raw);\n}\n\n/**\n * Parses without throwing; returns `null` on validation failure.\n *\n * @param raw - The unvalidated input from the consumer.\n * @returns The parsed {@link GanttInput} or `null` when the input is invalid.\n */\nexport function safeParseGanttInput(raw: GanttInputRaw): GanttInput | null {\n\tconst result = GanttInputSchema.safeParse(raw);\n\treturn result.success ? result.data : null;\n}\n","export type GanttErrorCode = 'PARENT_REFERENCE' | 'LINK_REFERENCE' | 'DEPENDENCY_CYCLE' | '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} 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 = Task & {\n\t/** Array of child task nodes in the tree hierarchy. */\n\tchildren: TaskNode[];\n\t/** 0 = root */\n\tdepth: number;\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 */\nexport function buildTaskTree(tasks: Task[]): TaskNode[] {\n\tconst map = new Map<number, TaskNode>();\n\tconst roots: TaskNode[] = [];\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: 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 3: 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 Link, type 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.\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 */\nexport function validateLinkRefs(tasks: Task[], links: Link[]): void {\n\tconst ids = new Set(tasks.map((t) => t.id));\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\t}\n}\n","export type LocaleLabelKey = 'ariaTask' | 'ariaMilestone' | 'addSubtaskTitle' | 'columnTaskName' | 'columnStartDate' | 'columnDuration' | '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\tcolumnTaskName: 'Task name',\n\tcolumnStartDate: 'Start time',\n\tcolumnDuration: 'Duration',\n\tcolumnQuarter: 'Q',\n};\n\nexport const CHART_LOCALE_EN_US: ChartLocale = {\n\tcode: 'en-US',\n\tlabels: EN_US_LABELS,\n\tweekStartsOn: 0,\n\tweekNumbering: 'iso',\n\tweekendDays: [0, 6],\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 CHART_LOCALE_EN_US;\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 * 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","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/** Hours → pixel width */\n\tdurationToWidth: (hours: number) => number;\n\t/** Pixel width → hours (float) */\n\twidthToDuration: (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 msPerHour = 3_600_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\tdurationToWidth(hours: number): number {\n\t\t\treturn hours * msPerHour * pxPerMs;\n\t\t},\n\t\twidthToDuration(px: number): number {\n\t\t\treturn (px * msPerPx) / msPerHour;\n\t\t},\n\t};\n}\n","import {type TaskNode} from '../domain/tree.ts';\nimport {type PixelMapper} from './pixelMapper.ts';\nimport {parseDate, addHours} 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\ttype: '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\tconst type = task.type ?? 'task';\n\n\t\tif (type === '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\ttype: '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 width = Math.max(mapper.durationToWidth(task.durationHours), 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\ttype,\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\tconst end = addHours(start, task.durationHours);\n\t\tif (start.getTime() < minMs) {\n\t\t\tminMs = start.getTime();\n\t\t}\n\t\tif (end.getTime() > maxMs) {\n\t\t\tmaxMs = end.getTime();\n\t\t}\n\t}\n\n\treturn [addHours(new Date(minMs), -paddingHours), addHours(new Date(maxMs), paddingHours)];\n}\n","import {type Link} from '../validation/schemas.ts';\nimport {type BarLayout} from '../timeline/layoutEngine.ts';\nimport {MILESTONE_HALF} 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\t/** Ordered vertices of the orthogonal polyline (source → target). */\n\tpoints: Point[];\n};\n\nconst TURN_MARGIN = 12; // px gap before/after bar for routing clearance\n\n/**\n * Produces the vertex list for an orthogonal connector between src and tgt.\n *\n * Link semantics:\n * FS = source.finish → target.start (most common)\n * SS = source.start → target.start\n * FF = source.finish → target.finish\n * SF = source.start → target.finish\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 `Point` vertices.\n */\nfunction route(type: Link['type'], src: BarLayout, tgt: BarLayout): Point[] {\n\tlet sx: number, tx: number;\n\tconst sy = src.centerY;\n\tconst ty = tgt.centerY;\n\n\tswitch (type) {\n\t\tcase 'FS': {\n\t\t\tsx = src.type === 'milestone' ? src.x + MILESTONE_HALF : src.x + src.width;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x - MILESTONE_HALF : tgt.x;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'SS': {\n\t\t\tsx = src.type === 'milestone' ? src.x - MILESTONE_HALF : src.x;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x - MILESTONE_HALF : tgt.x;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'FF': {\n\t\t\tsx = src.type === 'milestone' ? src.x + MILESTONE_HALF : src.x + src.width;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x + MILESTONE_HALF : tgt.x + tgt.width;\n\t\t\tbreak;\n\t\t}\n\t\tcase 'SF': {\n\t\t\tsx = src.type === 'milestone' ? src.x - MILESTONE_HALF : src.x;\n\t\t\ttx = tgt.type === 'milestone' ? tgt.x + MILESTONE_HALF : tgt.x + tgt.width;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Same row: direct horizontal\n\tif (Math.abs(sy - ty) < 1) {\n\t\treturn [\n\t\t\t{x: sx, y: sy},\n\t\t\t{x: tx, y: ty},\n\t\t];\n\t}\n\n\t// Forward path: midpoint between sx and tx\n\tif (sx <= tx) {\n\t\tconst midX = sx + Math.max(TURN_MARGIN, (tx - sx) / 2);\n\t\treturn [\n\t\t\t{x: sx, y: sy},\n\t\t\t{x: midX, y: sy},\n\t\t\t{x: midX, y: ty},\n\t\t\t{x: tx, y: ty},\n\t\t];\n\t}\n\n\t// Backward path: loop around via margins\n\tconst loopX = tx - TURN_MARGIN;\n\treturn [\n\t\t{x: sx, y: sy},\n\t\t{x: sx + TURN_MARGIN, y: sy},\n\t\t{x: sx + TURN_MARGIN, y: (sy + ty) / 2},\n\t\t{x: loopX, y: (sy + ty) / 2},\n\t\t{x: loopX, y: ty},\n\t\t{x: tx, y: ty},\n\t];\n}\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\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","/**\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} from '../../validation/schemas.ts';\nimport {type TaskNode} from '../../domain/tree.ts';\n\nexport type GridColumn = {\n\tid: string;\n\theader: string;\n\twidth: string;\n\talign?: 'left' | 'center' | 'right';\n\tvisible?: boolean;\n\tfield?: keyof Task;\n\tformat?: (value: unknown, task: Task, 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 time',\n\t\twidth: '90px',\n\t\tfield: 'startDate',\n\t\tformat: (value, _task, _row, locale) => formatDisplayDate(String(value), locale),\n\t},\n\t{\n\t\tid: 'durationHours',\n\t\theader: 'Duration',\n\t\twidth: '68px',\n\t\tfield: 'durationHours',\n\t\tformat: (value) => ((value as number) > 0 ? String(value) : '—'),\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: 'durationHours',\n\t\t\theader: locale.labels?.columnDuration ?? EN_US_LABELS.columnDuration,\n\t\t\twidth: '68px',\n\t\t\tfield: 'durationHours',\n\t\t\tformat: (value) => ((value as number) > 0 ? String(value) : '—'),\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$/;\nconst FR_RE = /^(\\d+(?:\\.\\d+)?)fr$/;\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 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\tonSelect: (id: number) => void;\n\tonRowClick: (payload: {id: number; task: Task}) => void;\n\tonTaskEditIntent: (payload: {id: number; source: 'grid'; trigger: 'doubleClick'; task: Task}) => void;\n\tonAdd: (id: number) => void;\n};\n\nfunction toTask(row: TaskNode): Task {\n\treturn {\n\t\tid: row.id,\n\t\ttext: row.text,\n\t\tstartDate: row.startDate,\n\t\tdurationHours: row.durationHours,\n\t\tpercentComplete: row.percentComplete,\n\t\ttype: row.type,\n\t\topen: row.open,\n\t\t...(row.parent === undefined ? {} : {parent: row.parent}),\n\t\t...(row.color === undefined ? {} : {color: row.color}),\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 ? '▾' : '▸';\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.type === '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 = 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 = rawValue !== null && rawValue !== undefined ? String(rawValue) : '';\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.onAdd(row.id);\n\t});\n\n\treturn btn;\n}\n\nfunction buildCell(column: GridColumn, row: TaskNode, expandedIds: Set<number>, cbs: LeftPaneCallbacks, locale: ChartLocale): 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 buildAddButton(row, cbs, locale);\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): 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.onSelect(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));\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 */\nexport function renderLeftPane(container: HTMLElement, state: GanttState, cbs: LeftPaneCallbacks, columns: GridColumn[]): 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));\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 * @returns The header DOM element.\n */\nexport function buildLeftPaneHeader(columns: GridColumn[]): 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\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_SIZE = 6;\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 * @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\tsetAttrs(svg, {\n\t\twidth: totalWidth,\n\t\theight: totalHeight,\n\t});\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: '9',\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: 'M 0 1 L 10 5 L 0 9 Z', 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\t'stroke-dasharray': valid ? 'none' : '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 */\nexport function updateDependencyLayer(\n\tsvg: SVGSVGElement,\n\tlinks: RoutedLink[],\n\ttotalWidth: number,\n\ttotalHeight: number,\n\tselectedTaskId: number | null,\n\thighlightLinkedDependenciesOnSelect: boolean,\n): void {\n\tsetAttrs(svg, {width: totalWidth, height: totalHeight});\n\n\t// Remove existing paths (keep defs at index 0, and keep ghost path)\n\tconst toRemove: Element[] = [];\n\tfor (let i = 1; i < svg.children.length; i++) {\n\t\tconst child = svg.children[i];\n\t\tif (child !== undefined && !child.classList.contains('gantt-ghost-line')) {\n\t\t\ttoRemove.push(child);\n\t\t}\n\t}\n\tfor (const node of toRemove) {\n\t\tsvg.removeChild(node);\n\t}\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\tlet d = `M ${points[0]?.x ?? 0},${points[0]?.y ?? 0}`;\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst p = points[i];\n\t\t\tif (p !== undefined) {\n\t\t\t\td += ` L ${p.x},${p.y}`;\n\t\t\t}\n\t\t}\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});\n\t\tsvg.append(path);\n\t}\n}\n","import {type TaskNode} from '../../domain/tree.ts';\nimport {type PixelMapper} from '../../timeline/pixelMapper.ts';\nimport {parseDate, addHours} from '../../domain/dateMath.ts';\nimport {type Task} from '../../validation/schemas.ts';\nimport {type GanttCallbacks} from '../gantt-chart.ts';\n\nfunction toTask(row: TaskNode): Task {\n\treturn {\n\t\tid: row.id,\n\t\ttext: row.text,\n\t\tstartDate: row.startDate,\n\t\tdurationHours: row.durationHours,\n\t\tpercentComplete: row.percentComplete,\n\t\ttype: row.type,\n\t\topen: row.open,\n\t\t...(row.parent === undefined ? {} : {parent: row.parent}),\n\t\t...(row.color === undefined ? {} : {color: row.color}),\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: GanttCallbacks): () => void {\n\t// ── Move ───────────────────────────────────────────────────────────────\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.onSelect?.(task.id);\n\n\t\tconst startX = e.clientX;\n\t\tconst originDate = parseDate(task.startDate);\n\t\tconst mapper = getMapper(); // snapshot at mousedown\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst hours = Math.round(mapper.widthToDuration(dx));\n\t\t\tcbs.onMove?.({id: task.id, startDate: addHours(originDate, hours)});\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}\n\n\t\tbarEl.style.cursor = 'grabbing';\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\t// ── Resize ─────────────────────────────────────────────────────────────\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\tconst origDur = task.durationHours;\n\t\tconst mapper = getMapper();\n\n\t\tfunction onMove(me: PointerEvent): void {\n\t\t\tconst dx = me.clientX - startX;\n\t\t\tconst hoursDelta = Math.round(mapper.widthToDuration(dx));\n\t\t\tcbs.onResize?.({id: task.id, durationHours: Math.max(1, origDur + hoursDelta)});\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}\n\n\t\twindow.addEventListener('pointermove', onMove);\n\t\twindow.addEventListener('pointerup', onUp);\n\t}\n\n\tfunction onBarClick(event: MouseEvent): void {\n\t\tif (event.detail !== 2) {\n\t\t\treturn;\n\t\t}\n\t\tcbs.onTaskEditIntent?.({id: task.id, source: 'bar', trigger: 'doubleClick', task: toTask(task)});\n\t}\n\n\tbarEl.addEventListener('pointerdown', onBarDown);\n\tbarEl.addEventListener('click', onBarClick);\n\tresizeHandleEl.addEventListener('pointerdown', onResizeDown);\n\n\treturn () => {\n\t\tbarEl.removeEventListener('pointerdown', onBarDown);\n\t\tbarEl.removeEventListener('click', onBarClick);\n\t\tresizeHandleEl.removeEventListener('pointerdown', onResizeDown);\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: GanttCallbacks): () => void {\n\tfunction onClick(): void {\n\t\tcbs.onSelect?.(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.onTaskEditIntent?.({id: taskId, source: 'milestone', trigger: 'doubleClick', 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 {type GanttCallbacks} from '../gantt-chart.ts';\nimport {showGhostLine, hideGhostLine} from '../dom/dependencyLayer.ts';\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: GanttCallbacks,\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} 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 {type GanttCallbacks} from '../gantt-chart.ts';\nimport {startOfDay} from '../../domain/dateMath.ts';\nimport {type ChartLocale, EN_US_LABELS, formatLabel} from '../../locale.ts';\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\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}\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\treturn {\n\t\tscrollContainer,\n\t\tstripeContainer,\n\t\tabsoluteLayer,\n\t\tsvgLayer,\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: GanttCallbacks,\n): void {\n\tconst selected = task.id === selectedId;\n\tconst color = BAR_COLOR[layout.type] ?? 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.type === 'project' ? '3px' : '4px',\n\t\tcursor: '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\tif (layout.progressWidth > 0) {\n\t\tconst prog = el('div');\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\tpointerEvents: 'none',\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', () => {\n\t\tcbs.onSelect?.(task.id);\n\t});\n\tbar.addEventListener('keydown', (event) => {\n\t\tif (event.key === 'Enter' || event.key === ' ') {\n\t\t\tevent.preventDefault();\n\t\t\tcbs.onSelect?.(task.id);\n\t\t}\n\t});\n\n\t// Resize handle\n\tconst handle = el('div');\n\thandle.className = 'gantt-resize-handle';\n\tcss(handle, {\n\t\tposition: 'absolute',\n\t\tright: '0',\n\t\ttop: '0',\n\t\twidth: '8px',\n\t\theight: '100%',\n\t\tcursor: 'ew-resize',\n\t\tzIndex: '1',\n\t\ttouchAction: 'none',\n\t});\n\tbar.append(handle);\n\n\tlayer.insertBefore(bar, svgLayer);\n\n\tconst cleanupDrag = attachDrag(bar, handle, task, () => state.mapper, cbs);\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\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t} = {bar, resizeHandle: handle, cleanupDrag};\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\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: GanttCallbacks,\n\tstate: GanttState,\n): void {\n\tconst selected = task.id === selectedId;\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: '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.onSelect?.(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\tconst cleanupDrag = attachMilestoneClick(diamond, task.id, cbs);\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\tconst entry: {\n\t\tbar: HTMLElement;\n\t\tresizeHandle: HTMLElement;\n\t\tcleanupDrag: () => void;\n\t\tcleanupLinkHandles?: () => void;\n\t} = {bar: diamond, resizeHandle: dummy, cleanupDrag};\n\tif (cleanupLinkHandles !== undefined) {\n\t\tentry.cleanupLinkHandles = cleanupLinkHandles;\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: GanttCallbacks): 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} of barRegistry.values()) {\n\t\tcleanupDrag();\n\t\tcleanupLinkHandles?.();\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 within timeline bounds)\n\tconst todayX = mapper.toX(new Date());\n\tconst todayLineWidth = 2;\n\tif (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.type === 'milestone') {\n\t\t\trenderMilestone(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, cbs, state);\n\t\t} else {\n\t\t\trenderBar(absoluteLayer, svgLayer, task, layout, selectedId, barRegistry, state, cbs);\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);\n}\n","import {SpecialDaySchema, type 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.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 {type GanttInput, type SpecialDay, type Task} 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 {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 {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\nexport type OnTaskSelect = (taskId: number | null) => void;\nexport type OnTaskMove = (payload: {id: number; startDate: Date}) => void;\nexport type OnTaskResize = (payload: {id: number; durationHours: number}) => void;\nexport type OnTaskAdd = (payload: {parentId: number}) => void;\nexport type OnTaskDoubleClick = (payload: {id: number; source: 'grid' | 'bar' | 'milestone'}) => void;\nexport type OnTaskEditIntent = (payload: {id: number; source: 'grid' | 'bar' | 'milestone'; trigger: 'doubleClick'; task: Task}) => void;\nexport type OnLinkCreate = (payload: {sourceTaskId: number; targetTaskId: number; type: 'FS'}) => void;\n\nexport type GanttCallbacks = {\n\tonSelect?: OnTaskSelect;\n\tonMove?: OnTaskMove;\n\tonResize?: OnTaskResize;\n\tonAdd?: OnTaskAdd;\n\tonTaskDoubleClick?: OnTaskDoubleClick;\n\tonTaskEditIntent?: OnTaskEditIntent;\n\tonLinkCreate?: OnLinkCreate;\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\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} & GanttCallbacks;\n\nexport type GanttInstance = {\n\tupdate: (input: GanttInput) => void;\n\tsetScale: (scale: TimeScale) => void;\n\tselect: (id: number | null) => void;\n\tcollapseAll: () => void;\n\texpandAll: () => void;\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 * @example\n * ```ts\n * const chart = new GanttChart(document.getElementById('chart')!, input, {\n * locale: 'de-DE',\n * theme: 'dark',\n * });\n * ```\n */\nexport class GanttChart implements GanttInstance {\n\treadonly #container: HTMLElement;\n\treadonly #opts: GanttOptions;\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\t#taskIndex: Map<number, number>;\n\t#lastGridClick: {id: number; atMs: number} | null = null;\n\t#userSplitWidth: number | null = null;\n\n\treadonly #height: number;\n\treadonly #locale: ChartLocale;\n\treadonly #timelineMinWidth: number;\n\treadonly #columns: GridColumn[];\n\treadonly #leftPaneDefaultWidth: number;\n\treadonly #weekendDays: Set<number>;\n\treadonly #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#leftBody!: HTMLElement;\n\t#rightPane!: HTMLElement;\n\t#rightHeader!: HTMLElement;\n\t#rightPaneRefs!: RightPaneRefs;\n\treadonly #cbs: GanttCallbacks;\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 *\n\t * @param container - The host `HTMLElement` the chart will be appended to.\n\t * @param opts - Configuration and callback 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.#taskIndex = new Map();\n\t\tthis.#locale = resolveChartLocale(opts.locale);\n\t\tthis.#columns = opts.gridColumns ?? gridColumnDefaults(this.#locale);\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 = {\n\t\t\tonSelect: (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\topts.onSelect?.(this.#selectedId);\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonTaskDoubleClick: (payload): void => {\n\t\t\t\topts.onTaskDoubleClick?.(payload);\n\t\t\t},\n\t\t\tonTaskEditIntent: (payload): void => {\n\t\t\t\topts.onTaskEditIntent?.(payload);\n\t\t\t\topts.onTaskDoubleClick?.({id: payload.id, source: payload.source});\n\t\t\t},\n\t\t\tonMove: (payload): void => {\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\topts.onMove?.(payload);\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonResize: (payload): void => {\n\t\t\t\tthis.#patchTask(payload.id, {durationHours: payload.durationHours});\n\t\t\t\topts.onResize?.(payload);\n\t\t\t\tthis.#scheduleRender();\n\t\t\t},\n\t\t\tonLeftPaneWidthChange: (width): void => {\n\t\t\t\topts.onLeftPaneWidthChange?.(width);\n\t\t\t},\n\t\t\tonGridColumnsChange: (updatedColumns): void => {\n\t\t\t\topts.onGridColumnsChange?.(updatedColumns);\n\t\t\t},\n\t\t\tonLinkCreate: (payload): void => {\n\t\t\t\topts.onLinkCreate?.(payload);\n\t\t\t},\n\t\t};\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/**\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: GanttInput): void {\n\t\tthis.#assertAlive();\n\t\tvalidateLinkRefs(newInput.tasks, newInput.links);\n\t\tdetectCycles(newInput.tasks, newInput.links);\n\t\tthis.#input = newInput;\n\t\tthis.#taskIndex = buildTaskIndex(newInput.tasks);\n\t\tthis.#expandedIds = getInitialExpandedIds(newInput.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 * Switches the time scale and re-renders.\n\t *\n\t * @param scale - The new {@link TimeScale} to display.\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic setScale(scale: TimeScale): void {\n\t\tthis.#assertAlive();\n\t\tthis.#scale = scale;\n\t\tthis.#scheduleRender();\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 * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic select(id: number | null): void {\n\t\tthis.#assertAlive();\n\t\tthis.#selectedId = id;\n\t\tthis.#opts.onSelect?.(id);\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 * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic collapseAll(): void {\n\t\tthis.#assertAlive();\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}\n\n\t/**\n\t * Expands all expandable groups in the task tree.\n\t *\n\t * @throws {GanttError} When the instance has been destroyed.\n\t */\n\tpublic expandAll(): void {\n\t\tthis.#assertAlive();\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}\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} of this.#rightPaneRefs.barRegistry.values()) {\n\t\t\tcleanupDrag();\n\t\t\tcleanupLinkHandles?.();\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};\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.onTaskEditIntent?.({id: payload.id, source: 'grid', trigger: 'doubleClick', task: payload.task});\n\t\t\treturn;\n\t\t}\n\t\tthis.#lastGridClick = {id: payload.id, atMs: now};\n\t\tthis.#cbs.onSelect?.(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\n\t\tconst mapper = createPixelMapper(this.#scale, vpStart);\n\t\tconst totalWidth = Math.ceil(mapper.toX(vpEnd)) + 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\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: vpEnd,\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\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\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\tif (this.#expandedIds.has(id)) {\n\t\t\t\t\t\tthis.#expandedIds.delete(id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#expandedIds.add(id);\n\t\t\t\t\t}\n\t\t\t\t\tthis.#scheduleRender();\n\t\t\t\t},\n\t\t\t\tonSelect: (id) => this.#cbs.onSelect?.(id),\n\t\t\t\tonRowClick: (payload) => {\n\t\t\t\t\tthis.#handleGridClick(payload);\n\t\t\t\t},\n\t\t\t\tonTaskEditIntent: (payload) => this.#cbs.onTaskEditIntent?.(payload),\n\t\t\t\tonAdd: (id) => this.#cbs.onAdd?.({parentId: id}),\n\t\t\t},\n\t\t\tthis.#columns,\n\t\t);\n\t\trenderRightPane(this.#rightPaneRefs, state, this.#cbs);\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);\n\t\tleftHeader.append(headerEl);\n\t\tleftPane.append(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.#cbs.onSelect?.(null);\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.#cbs.onSelect?.(null);\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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"}