@workiom/frappe-gantt 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -86,7 +86,8 @@ Frappe Gantt offers a wide range of options to customize your chart.
86
86
  | `column_width` | Width of each column in the timeline. | Any positive integer. | 45 |
87
87
  | `critical_path` | Automatically calculate and highlight the critical path. | `true`, `false` | `false` |
88
88
  | `date_format` | Format for displaying dates. | Any valid JS date format string. | `YYYY-MM-DD` |
89
- | `dependencies_type` | How dependent tasks behave when parent tasks move. | `fixed`, `finish-to-start`, `start-to-start`, `finish-to-finish`, `start-to-finish` | `fixed` |
89
+ | `dependencies_type` | Sets the default relationship type used to validate each arrow (turns it red on violation). Dragging is always free. | `finish-to-start`, `start-to-start`, `finish-to-finish`, `start-to-finish` | `finish-to-start` |
90
+ | `dependency_shifting` | Controls how dependent tasks shift after a bar is dropped. See Dependency Shifting section below. | `none`, `maintain_buffer_all`, `maintain_buffer_downstream`, `consume_buffer` | `none` |
90
91
  | `upper_header_height` | Height of the upper header in the timeline (in pixels). | Any positive integer. | `45` |
91
92
  | `lower_header_height` | Height of the lower header in the timeline (in pixels). | Any positive integer. | `30` |
92
93
  | `snap_at` | Snap tasks at particular intervel while resizing or dragging. | Any _interval_ (see below) | `1d` |
@@ -96,7 +97,6 @@ Frappe Gantt offers a wide range of options to customize your chart.
96
97
  | `ignore` | Ignored areas in the rendering | `weekend` _or_ Array of strings or date objects (`weekend` can be present to the array also). | `[]` |
97
98
  | `language` | Language for localization. | ISO 639-1 codes like `en`, `fr`, `es`. | `en` |
98
99
  | `lines` | Determines which grid lines to display. | `none` for no lines, `vertical` for only vertical lines, `horizontal` for only horizontal lines, `both` for complete grid. | `both` |
99
- | `move_dependencies` | Whether moving a task automatically moves its dependencies. | `true`, `false` | `true` |
100
100
  | `padding` | Padding around task bars (in pixels). | Any positive integer. | `18` |
101
101
  | `popup_on` | Event to trigger the popup display. | `click` _or_ `hover` | `click` |
102
102
  | `readonly_progress` | Disables editing task progress. | `true`, `false` | `false` |
@@ -109,45 +109,39 @@ Frappe Gantt offers a wide range of options to customize your chart.
109
109
  | `view_mode` | The initial view mode of the Gantt chart. | `Day`, `Week`, `Month`, `Year`. | `Day` |
110
110
  | `view_mode_select` | Allows selecting the view mode from a dropdown. | `true`, `false` | `false` |
111
111
 
112
- Apart from these ones, three options - `popup`, `view_modes` (plural, not singular), and `dependencies_type` - have additional details and are listed separately below.
112
+ Apart from these ones, two options - `popup` and `view_modes` (plural, not singular) - have additional details and are listed separately below. `dependencies_type` is also described in more detail in the Dependencies Type section below.
113
113
 
114
114
  #### Dependencies Type Configuration
115
115
 
116
- The `dependencies_type` option controls how dependent tasks behave when their parent tasks are moved. This can be set globally for all tasks or overridden per task.
116
+ The `dependencies_type` option controls how dependent tasks behave when their parent tasks are moved. This is set globally and can be overridden per dependency entry (see the task `dependencies` format below).
117
117
 
118
118
  **Available Types:**
119
119
 
120
- - **`fixed`** (default): Maintains backward compatibility. When `move_dependencies: true`, dependent tasks move together with parent during drag.
121
-
122
- - **`finish-to-start`**: Most common in project management. The dependent task can only start after the parent finishes.
120
+ - **`finish-to-start`** (default): Most common in project management. The dependent task can only start after the parent finishes.
123
121
  - Constraint: Dependent start date ≥ Parent end date
124
- - Auto-update: If parent ends after dependent starts, dependent moves forward
125
122
  - Example: Development can only start after Design finishes
126
123
 
127
124
  - **`start-to-start`**: The dependent task can only start after the parent starts.
128
125
  - Constraint: Dependent start date ≥ Parent start date
129
- - Auto-update: If parent starts after dependent, dependent moves forward
130
126
  - Example: Testing can start after Development starts (parallel work)
131
127
 
132
128
  - **`finish-to-finish`**: The dependent task can only finish after the parent finishes.
133
129
  - Constraint: Dependent end date ≥ Parent end date
134
- - Auto-update: If parent ends after dependent, dependent extends
135
130
  - Example: Documentation must finish after Development finishes
136
131
 
137
132
  - **`start-to-finish`**: The dependent task can only finish after the parent starts (rare).
138
133
  - Constraint: Dependent end date ≥ Parent start date
139
- - Auto-update: If parent starts after dependent ends, dependent extends
140
134
  - Example: Legacy system runs until new system starts
141
135
 
142
136
  **Usage:**
143
137
 
144
138
  ```js
145
- // Global configuration
139
+ // Global configuration (fallback for all dependencies)
146
140
  let gantt = new Gantt("#gantt", tasks, {
147
141
  dependencies_type: 'finish-to-start'
148
142
  });
149
143
 
150
- // Per-task override
144
+ // Per-dependency override via the dependencies array
151
145
  let tasks = [
152
146
  {
153
147
  id: 'design',
@@ -160,17 +154,56 @@ let tasks = [
160
154
  name: 'Development',
161
155
  start: '2023-01-05',
162
156
  end: '2023-01-15',
163
- dependencies: 'design',
164
- dependencies_type: 'finish-to-start' // Overrides global setting
157
+ dependencies: [
158
+ { id: 'design', type: 'finish-to-start' } // Overrides global setting
159
+ ]
165
160
  }
166
161
  ];
167
162
  ```
168
163
 
169
164
  **Behavior:**
170
- - When a parent task is moved, dependents automatically adjust if constraints would be violated
171
- - Users cannot drag dependent tasks to positions that violate constraints
172
- - Updates cascade through dependency chains (A B C)
173
- - All dependency types respect ignored dates/weekends
165
+ - Dragging is always free tasks can be moved to any position
166
+ - When a dependency constraint is violated, the arrow turns red
167
+ - Each arrow is validated independently based on its own `type`
168
+ - Constraints respect ignored dates/weekends
169
+
170
+ #### Dependency Shifting Configuration
171
+
172
+ The `dependency_shifting` option controls how dependent tasks respond when a bar is dragged or resized.
173
+
174
+ **Available Modes:**
175
+
176
+ - **`none`** (default): No shifting. Dependency arrows may visually overlap — no correction is applied.
177
+
178
+ - **`maintain_buffer_all`**: Shifts tasks by the same delta to preserve all gaps. Direction depends on the interaction:
179
+ - **Drag**: both upstream and downstream tasks shift
180
+ - **Right-resize** (end date changes): downstream tasks shift
181
+ - **Left-resize** (start date changes): upstream tasks shift
182
+
183
+ - **`maintain_buffer_downstream`**: Only downstream (child) tasks ever shift — regardless of whether the bar was dragged or resized. Left-resize does nothing.
184
+
185
+ - **`consume_buffer`**: Dependency-type-aware shifting. A shift only happens when a real conflict exists — remaining buffer is consumed silently. When buffer is exhausted, the minimum required shift is applied. Direction follows the same rules as `maintain_buffer_all` (drag → both, right-resize → downstream, left-resize → upstream).
186
+
187
+ Conflict conditions per dependency type:
188
+ | Type | Conflict when |
189
+ |---|---|
190
+ | `finish-to-start` | predecessor end > successor start |
191
+ | `start-to-start` | predecessor start > successor start |
192
+ | `finish-to-finish` | predecessor end > successor end |
193
+ | `start-to-finish` | predecessor start > successor end |
194
+
195
+ **Usage:**
196
+
197
+ ```js
198
+ let gantt = new Gantt("#gantt", tasks, {
199
+ dependency_shifting: 'consume_buffer'
200
+ });
201
+ ```
202
+
203
+ **Behavior notes:**
204
+ - Shifting fires after release (mouseup), not during live dragging or resizing
205
+ - When a task has multiple predecessors, the maximum required shift is applied (ensures all constraints are satisfied)
206
+ - Cycles in the dependency graph are safely skipped
174
207
 
175
208
  #### View Mode Configuration
176
209
 
@@ -1 +1 @@
1
- :root{--g-arrow-color: #1f2937;--g-arrow-critical-color: #f5c044;--g-arrow-invalid-color: #ff7676;--g-bar-color: #fff;--g-bar-border: #fff;--g-tick-color-thick: #ededed;--g-tick-color: #f3f3f3;--g-actions-background: #f3f3f3;--g-border-color: #ebeff2;--g-text-muted: #7c7c7c;--g-text-light: #fff;--g-text-dark: #171717;--g-progress-color: #dbdbdb;--g-handle-color: transparent;--g-weekend-label-color: #dcdce4;--g-expected-progress: #c4c4e9;--g-header-background: #fff;--g-row-color: #fdfdfd;--g-row-border-color: #c7c7c7;--g-today-highlight: #37352f;--g-popup-actions: #ebeff2;--g-weekend-highlight-color: #f7f7f7;--g-task-column-bg: #ffffff;--g-task-row-bg: #ffffff;--g-resize-handle-hover: rgba(59, 130, 246, .3);--g-resize-handle-active: rgba(59, 130, 246, .5)}.gantt-wrapper{display:flex;width:100%;position:relative}.gantt-wrapper.rtl{flex-direction:row-reverse}.gantt-container{line-height:14.5px;position:relative;overflow:auto;font-size:12px;height:var(--gv-grid-height);flex:1;min-width:0;border-radius:8px}.gantt-container .popup-wrapper{position:absolute;top:0;left:0;background:#fff;box-shadow:0 10px 24px -3px #0003;padding:10px;border-radius:5px;width:max-content;z-index:1000}.gantt-container .popup-wrapper .title{margin-bottom:2px;color:var(--g-text-dark);font-size:.85rem;font-weight:650;line-height:15px}.gantt-container .popup-wrapper .subtitle{color:var(--g-text-dark);font-size:.8rem;margin-bottom:5px}.gantt-container .popup-wrapper .details{color:var(--g-text-muted);font-size:.7rem}.gantt-container .popup-wrapper .actions{margin-top:10px;margin-left:3px}.gantt-container .popup-wrapper .action-btn{border:none;padding:5px 8px;background-color:var(--g-popup-actions);border-right:1px solid var(--g-text-light)}.gantt-container .popup-wrapper .action-btn:hover{background-color:brightness(97%)}.gantt-container .popup-wrapper .action-btn:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.gantt-container .popup-wrapper .action-btn:last-child{border-right:none;border-top-right-radius:4px;border-bottom-right-radius:4px}.gantt-container .grid-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);position:sticky;top:0;left:0;border-bottom:1px solid var(--g-row-border-color);z-index:1000}.gantt-container .lower-text,.gantt-container .upper-text{text-anchor:middle}.gantt-container .upper-header{height:var(--gv-upper-header-height)}.gantt-container .lower-header{height:var(--gv-lower-header-height)}.gantt-container .lower-text{font-size:12px;position:absolute;width:calc(var(--gv-column-width) * .8);height:calc(var(--gv-lower-header-height) * .8);margin:0 calc(var(--gv-column-width) * .1);align-content:center;text-align:center;color:var(--g-text-muted)}.gantt-container .upper-text{position:absolute;width:fit-content;font-weight:500;font-size:14px;color:var(--g-text-dark);height:calc(var(--gv-lower-header-height) * .66)}.gantt-container .current-upper{position:sticky;left:0!important;padding-left:17px;background:#fff}.gantt-container .side-header{position:sticky;top:0;right:0;float:right;z-index:1000;line-height:20px;font-weight:400;width:max-content;margin-left:auto;padding-right:10px;padding-top:10px;background:var(--g-header-background);display:flex}.gantt-container .side-header *{transition-property:background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:var(--g-actions-background);border-radius:.5rem;border:none;padding:5px 8px;color:var(--g-text-dark);font-size:14px;letter-spacing:.02em;font-weight:420;box-sizing:content-box;margin-right:5px}.gantt-container .side-header *:last-child{margin-right:0}.gantt-container .side-header *:hover{filter:brightness(97.5%)}.gantt-container .side-header select{width:60px;padding-top:2px;padding-bottom:2px}.gantt-container .side-header select:focus{outline:none}.gantt-container .date-range-highlight{background-color:var(--g-progress-color);border-radius:12px;height:calc(var(--gv-lower-header-height) - 6px);top:calc(var(--gv-upper-header-height) + 5px);position:absolute}.gantt-container .current-highlight{position:absolute;background:var(--g-today-highlight);width:1px;z-index:999}.gantt-container .current-ball-highlight{position:absolute;background:var(--g-today-highlight);z-index:1001;border-radius:50%}.gantt-container .current-date-highlight{background:var(--g-today-highlight);color:var(--g-text-light);border-radius:5px}.gantt-container .holiday-label{position:absolute;top:0;left:0;opacity:0;z-index:1000;background:--g-weekend-label-color;border-radius:5px;padding:2px 5px}.gantt-container .holiday-label.show{opacity:100}.gantt-container .extras{position:sticky;left:0}.gantt-container .extras .adjust{position:absolute;left:8px;top:calc(var(--gv-grid-height) - 60px);background-color:#000000b3;color:#fff;border:none;padding:8px;border-radius:3px}.gantt-container .hide{display:none}.gantt{user-select:none;-webkit-user-select:none;position:absolute;left:0}.gantt .grid-background{fill:none}.gantt .grid-row{fill:var(--g-row-color)}.gantt .row-line{stroke:var(--g-border-color)}.gantt .tick{stroke:var(--g-tick-color);stroke-width:.4}.gantt .tick.thick{stroke:var(--g-tick-color-thick);stroke-width:.7}.gantt .arrow{fill:none;stroke:var(--g-arrow-color);stroke-width:1.5}.gantt .arrow-critical{stroke:var(--g-arrow-critical-color)}.gantt .arrow-invalid{stroke:var(--g-arrow-invalid-color)}.gantt .bar-wrapper .bar{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:0;transition:stroke-width .3s ease}.gantt .bar-progress{fill:var(--g-progress-color);border-radius:4px}.gantt .bar-expected-progress{fill:var(--g-expected-progress)}.gantt .bar-invalid{fill:transparent;stroke:var(--g-bar-border);stroke-width:1;stroke-dasharray:5}:is(.gantt .bar-invalid)~.bar-label{fill:var(--g-text-light)}.gantt .bar-label{fill:var(--g-text-dark);dominant-baseline:central;font-family:Helvetica;font-size:13px;font-weight:400}.gantt .bar-label.big{fill:var(--g-text-dark);text-anchor:start}.gantt .handle{fill:var(--g-handle-color);opacity:0;transition:opacity .3s ease}.gantt .handle.active,.gantt .handle.visible{cursor:ew-resize;opacity:1}.gantt .handle.progress{fill:var(--g-text-muted)}.gantt .bar-wrapper{cursor:pointer}.gantt .bar-wrapper .bar{outline:1px solid var(--g-row-border-color);border-radius:3px}.gantt .bar-wrapper:hover .bar{transition:transform .3s ease}.gantt .bar-wrapper:hover .date-range-highlight{display:block}.gantt .add-task-icon{cursor:pointer;transition:opacity .2s ease}.gantt .add-task-icon .add-task-icon-bg{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:1;transition:all .2s ease}.gantt .add-task-icon .add-task-icon-plus{stroke:var(--g-text-dark);stroke-width:2;stroke-linecap:round;transition:stroke .2s ease}.gantt .add-task-icon.active .add-task-icon-bg,.gantt .add-task-icon:hover .add-task-icon-bg{fill:var(--g-progress-color);stroke:var(--g-progress-color)}.gantt .add-task-icon.active .add-task-icon-plus,.gantt .add-task-icon:hover .add-task-icon-plus{stroke:var(--g-text-light)}.task-column{flex-shrink:0;width:var(--gv-task-column-width, 150px);height:var(--gv-grid-height);background-color:var(--g-task-column-bg);border-right:1px solid var(--g-row-border-color);overflow-y:auto;overflow-x:hidden;-webkit-user-select:none;user-select:none;position:relative;scrollbar-width:none;-ms-overflow-style:none}.task-column::-webkit-scrollbar{display:none}.task-column-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);border-bottom:1px solid var(--g-row-border-color);position:sticky;top:0;z-index:1001;display:flex;align-items:center;padding:0 12px;font-weight:600;font-size:13px;color:var(--g-text-dark)}.task-column-content{position:relative;width:100%;padding-top:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);overflow:visible}.task-row{position:absolute;width:100%;padding:0 12px;display:flex;align-items:center;font-size:13px;color:var(--g-text-dark);border-bottom:1px solid var(--g-row-border-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:var(--g-task-row-bg)}.task-column-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;min-height:calc(var(--gv-task-column-content-height) + var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);cursor:col-resize;z-index:1002;background-color:transparent;transition:background-color .2s ease}.task-column-resize-handle:hover{background-color:var(--g-resize-handle-hover)}.task-column.resizing .task-column-resize-handle{background-color:var(--g-resize-handle-active)}.task-column.resizing{-webkit-user-select:none;user-select:none}.gantt-wrapper.rtl .task-column{border-right:none;border-left:1px solid var(--g-row-border-color)}.gantt-wrapper.rtl .task-column-resize-handle{right:auto;left:0}
1
+ :root{--g-arrow-color: #1f2937;--g-arrow-hover-color: #007bff;--g-arrow-critical-color: #f5c044;--g-arrow-invalid-color: #ff7676;--g-bar-color: #fff;--g-bar-border: #fff;--g-tick-color-thick: #ededed;--g-tick-color: #f3f3f3;--g-actions-background: #f3f3f3;--g-border-color: #ebeff2;--g-text-muted: #7c7c7c;--g-text-light: #fff;--g-text-dark: #171717;--g-progress-color: #dbdbdb;--g-handle-color: transparent;--g-weekend-label-color: #dcdce4;--g-expected-progress: #c4c4e9;--g-header-background: #fff;--g-row-color: #fdfdfd;--g-row-border-color: #c7c7c7;--g-today-highlight: #37352f;--g-popup-actions: #ebeff2;--g-weekend-highlight-color: #f7f7f7;--g-task-column-bg: #ffffff;--g-task-row-bg: #ffffff;--g-resize-handle-hover: rgba(59, 130, 246, .3);--g-resize-handle-active: rgba(59, 130, 246, .5)}.gantt-wrapper{display:flex;width:100%;position:relative}.gantt-wrapper.rtl{flex-direction:row-reverse}.gantt-container{line-height:14.5px;position:relative;overflow:auto;font-size:12px;height:var(--gv-grid-height);flex:1;min-width:0;border-radius:8px}.gantt-container .popup-wrapper{position:absolute;top:0;left:0;background:#fff;box-shadow:0 10px 24px -3px #0003;padding:10px;border-radius:5px;width:max-content;z-index:1000}.gantt-container .popup-wrapper .title{margin-bottom:2px;color:var(--g-text-dark);font-size:.85rem;font-weight:650;line-height:15px}.gantt-container .popup-wrapper .subtitle{color:var(--g-text-dark);font-size:.8rem;margin-bottom:5px}.gantt-container .popup-wrapper .details{color:var(--g-text-muted);font-size:.7rem}.gantt-container .popup-wrapper .actions{margin-top:10px;margin-left:3px}.gantt-container .popup-wrapper .action-btn{border:none;padding:5px 8px;background-color:var(--g-popup-actions);border-right:1px solid var(--g-text-light)}.gantt-container .popup-wrapper .action-btn:hover{background-color:brightness(97%)}.gantt-container .popup-wrapper .action-btn:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.gantt-container .popup-wrapper .action-btn:last-child{border-right:none;border-top-right-radius:4px;border-bottom-right-radius:4px}.gantt-container .grid-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);position:sticky;top:0;left:0;border-bottom:1px solid var(--g-row-border-color);z-index:1000}.gantt-container .lower-text,.gantt-container .upper-text{text-anchor:middle}.gantt-container .upper-header{height:var(--gv-upper-header-height)}.gantt-container .lower-header{height:var(--gv-lower-header-height)}.gantt-container .lower-text{font-size:12px;position:absolute;width:calc(var(--gv-column-width) * .8);height:calc(var(--gv-lower-header-height) * .8);margin:0 calc(var(--gv-column-width) * .1);align-content:center;text-align:center;color:var(--g-text-muted)}.gantt-container .upper-text{position:absolute;width:fit-content;font-weight:500;font-size:14px;color:var(--g-text-dark);height:calc(var(--gv-lower-header-height) * .66)}.gantt-container .current-upper{position:sticky;left:0!important;padding-left:17px;background:#fff}.gantt-container .side-header{position:sticky;top:0;right:0;float:right;z-index:1000;line-height:20px;font-weight:400;width:max-content;margin-left:auto;padding-right:10px;padding-top:10px;background:var(--g-header-background);display:flex}.gantt-container .side-header *{transition-property:background-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;background-color:var(--g-actions-background);border-radius:.5rem;border:none;padding:5px 8px;color:var(--g-text-dark);font-size:14px;letter-spacing:.02em;font-weight:420;box-sizing:content-box;margin-right:5px}.gantt-container .side-header *:last-child{margin-right:0}.gantt-container .side-header *:hover{filter:brightness(97.5%)}.gantt-container .side-header select{width:60px;padding-top:2px;padding-bottom:2px}.gantt-container .side-header select:focus{outline:none}.gantt-container .date-range-highlight{background-color:var(--g-progress-color);border-radius:12px;height:calc(var(--gv-lower-header-height) - 6px);top:calc(var(--gv-upper-header-height) + 5px);position:absolute}.gantt-container .current-highlight{position:absolute;background:var(--g-today-highlight);width:1px;z-index:999}.gantt-container .current-ball-highlight{position:absolute;background:var(--g-today-highlight);z-index:1001;border-radius:50%}.gantt-container .current-date-highlight{background:var(--g-today-highlight);color:var(--g-text-light);border-radius:5px}.gantt-container .holiday-label{position:absolute;top:0;left:0;opacity:0;z-index:1000;background:--g-weekend-label-color;border-radius:5px;padding:2px 5px}.gantt-container .holiday-label.show{opacity:100}.gantt-container .extras{position:sticky;left:0}.gantt-container .extras .adjust{position:absolute;left:8px;top:calc(var(--gv-grid-height) - 60px);background-color:#000000b3;color:#fff;border:none;padding:8px;border-radius:3px}.gantt-container .hide{display:none}.gantt{user-select:none;-webkit-user-select:none;position:absolute;left:0}.gantt .grid-background{fill:none}.gantt .grid-row{fill:var(--g-row-color)}.gantt .row-line{stroke:var(--g-border-color)}.gantt .tick{stroke:var(--g-tick-color);stroke-width:.4}.gantt .tick.thick{stroke:var(--g-tick-color-thick);stroke-width:.7}.gantt .arrow{fill:none;stroke:var(--g-arrow-color);stroke-width:1.5}.gantt .arrow-critical{stroke:var(--g-arrow-critical-color)}.gantt .arrow-invalid{stroke:var(--g-arrow-invalid-color)}.gantt .arrow-hover{stroke:var(--g-arrow-hover-color)}.gantt .bar-wrapper .bar{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:0;transition:stroke-width .3s ease}.gantt .bar-wrapper .bar.bar-arrow-critical{outline-color:var(--g-arrow-critical-color)}.gantt .bar-wrapper .bar.bar-arrow-invalid{outline-color:var(--g-arrow-invalid-color)}.gantt .bar-progress{fill:var(--g-progress-color);border-radius:4px}.gantt .bar-expected-progress{fill:var(--g-expected-progress)}.gantt .bar-invalid{fill:transparent;stroke:var(--g-bar-border);stroke-width:1;stroke-dasharray:5}:is(.gantt .bar-invalid)~.bar-label{fill:var(--g-text-light)}.gantt .bar-label{fill:var(--g-text-dark);dominant-baseline:central;font-family:Helvetica;font-size:13px;font-weight:400}.gantt .bar-label.big{fill:var(--g-text-dark);text-anchor:start}.gantt .handle{fill:var(--g-handle-color);opacity:0;transition:opacity .3s ease}.gantt .handle.active,.gantt .handle.visible{cursor:ew-resize;opacity:1}.gantt .handle.progress{fill:var(--g-text-muted)}.gantt .bar-wrapper{cursor:pointer}.gantt .bar-wrapper .bar{outline:1px solid var(--g-row-border-color);border-radius:3px}.gantt .bar-wrapper:hover .bar{transition:transform .3s ease}.gantt .bar-wrapper:hover .date-range-highlight{display:block}.gantt .add-task-icon{cursor:pointer;transition:opacity .2s ease}.gantt .add-task-icon .add-task-icon-bg{fill:var(--g-bar-color);stroke:var(--g-bar-border);stroke-width:1;transition:all .2s ease}.gantt .add-task-icon .add-task-icon-plus{stroke:var(--g-text-dark);stroke-width:2;stroke-linecap:round;transition:stroke .2s ease}.gantt .add-task-icon.active .add-task-icon-bg,.gantt .add-task-icon:hover .add-task-icon-bg{fill:var(--g-progress-color);stroke:var(--g-progress-color)}.gantt .add-task-icon.active .add-task-icon-plus,.gantt .add-task-icon:hover .add-task-icon-plus{stroke:var(--g-text-light)}.task-column{flex-shrink:0;width:var(--gv-task-column-width, 150px);height:var(--gv-grid-height);background-color:var(--g-task-column-bg);border-right:1px solid var(--g-row-border-color);overflow-y:auto;overflow-x:hidden;-webkit-user-select:none;user-select:none;position:relative;scrollbar-width:none;-ms-overflow-style:none}.task-column::-webkit-scrollbar{display:none}.task-column-header{height:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);background-color:var(--g-header-background);border-bottom:1px solid var(--g-row-border-color);position:sticky;top:0;z-index:1001;display:flex;align-items:center;padding:0 12px;font-weight:600;font-size:13px;color:var(--g-text-dark)}.task-column-content{position:relative;width:100%;padding-top:calc(var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);overflow:visible}.task-row{position:absolute;width:100%;padding:0 12px;display:flex;align-items:center;font-size:13px;color:var(--g-text-dark);border-bottom:1px solid var(--g-row-border-color);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:var(--g-task-row-bg)}.task-column-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;min-height:calc(var(--gv-task-column-content-height) + var(--gv-lower-header-height) + var(--gv-upper-header-height) + 10px);cursor:col-resize;z-index:1002;background-color:transparent;transition:background-color .2s ease}.task-column-resize-handle:hover{background-color:var(--g-resize-handle-hover)}.task-column.resizing .task-column-resize-handle{background-color:var(--g-resize-handle-active)}.task-column.resizing{-webkit-user-select:none;user-select:none}.gantt-wrapper.rtl .task-column{border-right:none;border-left:1px solid var(--g-row-border-color)}.gantt-wrapper.rtl .task-column-resize-handle{right:auto;left:0}