eru-grid 0.0.45 → 0.0.47

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.
@@ -168,6 +168,53 @@ function statusPillColors(color) {
168
168
  text: `rgb(${dark(r)}, ${dark(g)}, ${dark(b)})`,
169
169
  };
170
170
  }
171
+ /** Shown when a tag has no colour of its own. */
172
+ const TAG_PILL_FALLBACK = {
173
+ background: '#f5f5f5',
174
+ text: '#49454f',
175
+ dot: '#9e9e9e',
176
+ };
177
+ /**
178
+ * The colours for a tag pill, from the single colour the data model gives it.
179
+ *
180
+ * A tag is deliberately not a status. Status owns the ringed pill — a tint fill
181
+ * inside a full-saturation border — because a record has exactly one status and
182
+ * it is the state the row is judged by. A tag field holds a list, so the same
183
+ * treatment repeated four times across one cell turns into four competing
184
+ * outlines. Tags instead get a tint fill with no border and a full-saturation
185
+ * dot ahead of the label: quieter than status at a glance, still carrying the
186
+ * palette colour at full strength in the dot so a pale entry stays identifiable.
187
+ *
188
+ * The fill is lightened 88% toward white and the text darkened 35% — slightly
189
+ * more contrast than the status pill, since with no border the fill alone has
190
+ * to describe the pill's edge.
191
+ *
192
+ * Lives here beside `statusPillColors` because eru-grid's tag cell and
193
+ * eru-studio's tag control paint the same values, and two copies of this
194
+ * arithmetic is two ways for one field to look different depending on which
195
+ * control renders it.
196
+ */
197
+ function tagPillColors(color) {
198
+ const hex = String(color ?? '').replace('#', '');
199
+ const expanded = hex.length === 3 ? hex.split('').map(c => c + c).join('') : hex;
200
+ if (expanded.length !== 6)
201
+ return { ...TAG_PILL_FALLBACK };
202
+ const value = parseInt(expanded, 16);
203
+ if (isNaN(value))
204
+ return { ...TAG_PILL_FALLBACK };
205
+ const r = (value >> 16) & 255;
206
+ const g = (value >> 8) & 255;
207
+ const b = value & 255;
208
+ const lighten = 0.88;
209
+ const darken = 0.35;
210
+ const lit = (channel) => Math.min(255, Math.round(channel + (255 - channel) * lighten));
211
+ const dark = (channel) => Math.round(channel * (1 - darken));
212
+ return {
213
+ background: `rgb(${lit(r)}, ${lit(g)}, ${lit(b)})`,
214
+ text: `rgb(${dark(r)}, ${dark(g)}, ${dark(b)})`,
215
+ dot: `#${expanded}`,
216
+ };
217
+ }
171
218
  /** Short month names, for the `MMM` token. */
172
219
  const MONTH_SHORT_NAMES = [
173
220
  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
@@ -8638,36 +8685,11 @@ class TagComponent {
8638
8685
  this.valueChange.emit(updatedTags.length > 0 ? updatedTags : null);
8639
8686
  }
8640
8687
  getTagColor(tag) {
8641
- const cfg = this.config();
8642
- if (!cfg || !cfg.options) {
8643
- return { background: '#cccccc', color: '#000000' };
8644
- }
8645
- const options = cfg.options || [];
8646
- // Find option by name (tag value matches option.name)
8647
- const tagOption = options.find((opt) => {
8648
- return opt.name === tag;
8649
- });
8650
- if (!tagOption || !tagOption.color) {
8651
- return { background: '#cccccc', color: '#000000' };
8652
- }
8653
- const backgroundColor = tagOption.color;
8654
- // Function to determine text color based on background brightness
8655
- const getContrastYIQ = (hexcolor) => {
8656
- // Remove # if present
8657
- hexcolor = hexcolor.replace('#', '');
8658
- // Convert hex to RGB
8659
- const r = parseInt(hexcolor.substr(0, 2), 16);
8660
- const g = parseInt(hexcolor.substr(2, 2), 16);
8661
- const b = parseInt(hexcolor.substr(4, 2), 16);
8662
- // Calculate luminance
8663
- const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
8664
- // Return black for light backgrounds, white for dark backgrounds
8665
- return (yiq >= 128) ? '#000000' : '#ffffff';
8666
- };
8667
- return {
8668
- background: backgroundColor,
8669
- color: getContrastYIQ(backgroundColor)
8670
- };
8688
+ const options = this.config()?.options || [];
8689
+ // Data-model options carry `name`; panel-authored ones carry `label`/`value`.
8690
+ // Matching on `name` alone dropped the latter to the grey fallback.
8691
+ const tagOption = options.find((opt) => (opt?.name ?? opt?.label ?? opt?.value) === tag);
8692
+ return tagPillColors(tagOption?.color);
8671
8693
  }
8672
8694
  isTagSelected(tagValue) {
8673
8695
  return this.currentValue().includes(tagValue);
@@ -8730,7 +8752,7 @@ class TagComponent {
8730
8752
  this.newTagColor.set('#cccccc');
8731
8753
  }
8732
8754
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8733
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: TagComponent, isStandalone: true, selector: "eru-tag", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isEditable: { classPropertyName: "isEditable", publicName: "isEditable", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isDrillable: { classPropertyName: "isDrillable", publicName: "isDrillable", isSignal: true, isRequired: false, transformFunction: null }, columnWidth: { classPropertyName: "columnWidth", publicName: "columnWidth", isSignal: true, isRequired: false, transformFunction: null }, fieldSize: { classPropertyName: "fieldSize", publicName: "fieldSize", isSignal: true, isRequired: false, transformFunction: null }, eruGridStore: { classPropertyName: "eruGridStore", publicName: "eruGridStore", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus", drilldownClick: "drilldownClick", editModeChange: "editModeChange", newTagAdded: "newTagAdded" }, viewQueries: [{ propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true }], ngImport: i0, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"tag-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"tag-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || ''\"\n [multiple]=\"true\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"tag-panel\"\n (selectionChange)=\"onValueChange($event.value)\"\n (blur)=\"onBlur($event)\"\n (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n \n <mat-option disabled class=\"search-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n @if (isSearchable()) {\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"search-input\"\n [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n }\n <div class=\"select-all-container mat-mdc-option mdc-list-item\"\n [class.mdc-list-item--selected]=\"isAllSelected() || isIndeterminate()\"\n [class.select-all-partial]=\"isIndeterminate()\"\n (click)=\"toggleSelectAll(!isAllSelected()); $event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox select-all-checkbox\"\n [state]=\"isIndeterminate() ? 'indeterminate' : (isAllSelected() ? 'checked' : 'unchecked')\"></mat-pseudo-checkbox>\n <span class=\"mdc-list-item__primary-text select-all-text\">Select All</span>\n </div>\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\" \n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\" \n (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n <span class=\"tag-option\" \n [style.background]=\"getTagColor(option.value).background\" \n [style.color]=\"getTagColor(option.value).color\">\n {{ option.label }}\n </span>\n </mat-option>\n }\n\n <mat-option class=\"add-tag-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <div class=\"add-tag-container\" (click)=\"$event.stopPropagation()\">\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"add-tag-form-field\">\n <mat-label>Add new tag</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"add-tag-input\"\n [value]=\"newTagInput()\"\n (input)=\"onNewTagInputChange($any($event.target).value)\"\n (keydown.enter)=\"addNewTag()\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n <div class=\"add-tag-actions\">\n <input\n type=\"color\"\n class=\"add-tag-color-picker\"\n [value]=\"newTagColor()\"\n (input)=\"onNewTagColorChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n title=\"Select tag color\">\n <button\n mat-icon-button\n class=\"add-tag-button\"\n [disabled]=\"!canAddNewTag()\"\n (click)=\"addNewTag(); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n </mat-option>\n\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n <div \n class=\"tag-display\" \n [class.tag-display-editable]=\"isEditable()\"\n (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).color\">\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n </span>\n } @else {\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).color\">\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag-more\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n }\n </div>\n}\n\n", styles: [".tag-form-field{width:100%}.tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.tag-container{width:100%}.tag-display{width:100%;padding:8px 12px;min-height:30px;display:flex;flex-wrap:wrap;align-items:center;gap:4px;cursor:default}.tag-display.tag-display-editable{cursor:pointer}.tag-display.tag-display-editable:hover{background-color:#0000000a}.tag{display:inline-block;padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);border-radius:var(--grid-pill-radius, 12px);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 500);white-space:nowrap;line-height:1.2}.tag-more{display:inline-block;border-radius:var(--grid-pill-radius, 12px);background-color:var(--grid-surface-container-high, #f5f5f5);color:var(--grid-on-surface-variant, #49454f);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 700);font-style:italic;padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);white-space:nowrap;line-height:1.2}.drillable-value{display:flex;flex-wrap:wrap;gap:4px;align-items:center;cursor:pointer}.drillable-value .tag{text-decoration:underline}.add-option{position:sticky;position:-webkit-sticky;bottom:0;z-index:3;background:var(--grid-surface-container-high, #fff);box-shadow:0 -2px 8px -4px #00000017;border-top:1px solid var(--grid-outline-variant, #e0e0e0)}.search-option{padding:2px 4px!important;cursor:default!important;pointer-events:auto!important;width:100%!important;box-sizing:border-box!important;overflow:hidden!important}.search-option .mat-mdc-option{height:auto!important;padding:2px 4px!important;min-height:auto!important}.search-option .mat-mdc-option:hover{background:transparent!important}.search-option .mdc-list-item__primary-text{width:100%!important;max-width:100%!important;box-sizing:border-box!important;padding:0!important;margin:0!important;display:flex!important;flex-direction:column!important;gap:8px!important;opacity:1!important}.search-option .search-form-field{width:100%!important;max-width:100%!important;pointer-events:auto!important;box-sizing:border-box!important;margin:0!important}.search-option .search-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.search-option .search-form-field .mat-mdc-text-field-wrapper{padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-form-field .mat-mdc-form-field-infix{width:100%!important;max-width:100%!important;box-sizing:border-box!important;min-height:auto!important;padding:0!important}.search-option .search-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.search-option .select-all-container{padding:4px 0!important;min-height:auto!important;display:flex!important;align-items:center!important;pointer-events:auto!important;cursor:pointer!important;background:transparent!important}.search-option .select-all-container:hover{background:var(--grid-row-hover, rgba(0, 0, 0, .04))!important}.search-option .select-all-container .select-all-text{display:inline-flex!important;flex-direction:row!important;align-items:center!important;width:auto!important;max-width:none!important;gap:0!important;font-family:var(--grid-font-family, \"Poppins\")!important;font-size:var(--grid-font-size-body, 12px)!important;font-weight:500!important;color:var(--grid-on-surface, #1d1b20)!important}.search-option .select-all-container.select-all-partial .select-all-text:before,.search-option .select-all-container.select-all-partial .select-all-checkbox{opacity:.5}.tag-panel-footer{position:absolute;bottom:0;left:0;right:0;background:#fff;border-top:1px solid rgba(0,0,0,.12);padding:8px;z-index:10;box-shadow:0 -2px 4px #0000001a}.tag-panel-footer .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;pointer-events:auto}.tag-panel-footer .add-tag-form-field-wrapper{flex:1;min-width:0;position:relative}.tag-panel-footer .new-tag-input{width:100%;border:1px solid rgba(0,0,0,.38);border-radius:4px;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 12px;font-family:var(--grid-font-family, \"Poppins\")!important;box-sizing:border-box;cursor:text}.tag-panel-footer .new-tag-input:focus{border-color:var(--grid-primary, #6750a4);border-width:2px}.tag-panel-footer .add-tag-button{flex-shrink:0;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 16px!important;min-width:auto!important;pointer-events:auto!important;background-color:var(--grid-primary, #6750a4);color:#fff;border:none;border-radius:4px;cursor:pointer;font-family:var(--grid-font-family, \"Poppins\")!important}.tag-panel-footer .add-tag-button:hover:not([disabled]){opacity:.9}.tag-panel-footer .add-tag-button[disabled]{opacity:.5;cursor:not-allowed}.cdk-overlay-pane.tag-panel-overlay{position:relative;padding-bottom:60px!important}.cdk-overlay-pane.tag-panel-overlay .mat-mdc-select-panel{max-height:calc(100% - 60px)!important}.add-tag-option{position:sticky!important;background:var(--grid-surface, #fff)!important;bottom:-10px!important;z-index:10!important;padding:8px 8px 10px!important;margin-top:auto!important;margin-bottom:0!important;box-shadow:0 -2px 8px #00000026!important;border-top:1px solid rgba(0,0,0,.12)!important}.add-tag-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mat-mdc-option{min-height:auto!important;padding:0!important;height:auto!important}.add-tag-option .mat-mdc-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mdc-list-item__primary-text{width:100%!important;padding:0!important;margin:0!important}.add-tag-option .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;padding:0;margin-bottom:0}.add-tag-option .add-tag-form-field{flex:1;min-width:0}.add-tag-option .add-tag-form-field .mat-mdc-form-field-focus-overlay{background:transparent!important}.add-tag-option .add-tag-form-field .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field .mdc-notched-outline__trailing{border-color:var(--grid-outline-variant, #cac4d0)!important;border-width:1px!important}.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--grid-outline, #79747e)!important}.add-tag-option .add-tag-form-field .mdc-floating-label,.add-tag-option .add-tag-form-field label{color:var(--grid-on-surface-variant, #49454f)!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.add-tag-option .add-tag-form-field .mat-mdc-text-field-wrapper{background:transparent!important;padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-infix{min-height:auto!important;padding:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.add-tag-option .add-tag-actions{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;flex-shrink:0}.add-tag-option .add-tag-color-picker{flex-shrink:0;width:20px;height:20px;border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;padding:2px;background:transparent;box-sizing:border-box;margin:0 auto}.add-tag-option .add-tag-color-picker::-webkit-color-swatch-wrapper{padding:0}.add-tag-option .add-tag-color-picker::-webkit-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker::-moz-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker:hover{border-color:var(--grid-primary, #6750a4)}.add-tag-option .add-tag-color-picker:focus{outline:2px solid var(--grid-primary, #6750a4);outline-offset:2px}.add-tag-option .add-tag-button{flex-shrink:0;width:20px;height:20px;color:var(--grid-primary, #6750a4)!important;display:flex!important;align-items:center!important;justify-content:center!important;margin:0 auto}.add-tag-option .add-tag-button:not([disabled]){color:var(--grid-primary, #6750a4)!important}.add-tag-option .add-tag-button:not([disabled]):hover{background-color:#6750a414!important}.add-tag-option .add-tag-button[disabled]{opacity:.38;color:#00000061!important}.add-tag-option .add-tag-button mat-icon{font-size:24px;width:24px;height:24px;line-height:24px;display:flex;align-items:center;justify-content:center;margin-right:0}.tag-panel .search-option>mat-pseudo-checkbox,.tag-panel .search-option>.mat-mdc-option-pseudo-checkbox,.tag-panel .add-tag-option>mat-pseudo-checkbox,.tag-panel .add-tag-option>.mat-mdc-option-pseudo-checkbox{display:none!important}.tag-panel{min-width:200px!important}.tag-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.tag-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.tag-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}mat-option .mdc-list-item__primary-text{line-height:1.5!important;white-space:normal!important;display:flex!important;align-items:center!important}mat-option .tag-option{display:inline-block;padding:4px 8px;border-radius:12px;font-size:var(--grid-font-size-body, 12px);font-weight:500;white-space:nowrap;line-height:1.2}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i2$3.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i2$3.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "ngmodule", type: MatPseudoCheckboxModule }, { kind: "component", type: i1$1.MatPseudoCheckbox, selector: "mat-pseudo-checkbox", inputs: ["state", "disabled", "appearance"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
8755
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: TagComponent, isStandalone: true, selector: "eru-tag", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, isEditable: { classPropertyName: "isEditable", publicName: "isEditable", isSignal: true, isRequired: false, transformFunction: null }, isActive: { classPropertyName: "isActive", publicName: "isActive", isSignal: true, isRequired: false, transformFunction: null }, isDrillable: { classPropertyName: "isDrillable", publicName: "isDrillable", isSignal: true, isRequired: false, transformFunction: null }, columnWidth: { classPropertyName: "columnWidth", publicName: "columnWidth", isSignal: true, isRequired: false, transformFunction: null }, fieldSize: { classPropertyName: "fieldSize", publicName: "fieldSize", isSignal: true, isRequired: false, transformFunction: null }, eruGridStore: { classPropertyName: "eruGridStore", publicName: "eruGridStore", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur", focus: "focus", drilldownClick: "drilldownClick", editModeChange: "editModeChange", newTagAdded: "newTagAdded" }, viewQueries: [{ propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true }], ngImport: i0, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"tag-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"tag-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || ''\"\n [multiple]=\"true\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"tag-panel\"\n (selectionChange)=\"onValueChange($event.value)\"\n (blur)=\"onBlur($event)\"\n (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n \n <mat-option disabled class=\"search-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n @if (isSearchable()) {\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"search-input\"\n [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n }\n <div class=\"select-all-container mat-mdc-option mdc-list-item\"\n [class.mdc-list-item--selected]=\"isAllSelected() || isIndeterminate()\"\n [class.select-all-partial]=\"isIndeterminate()\"\n (click)=\"toggleSelectAll(!isAllSelected()); $event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox select-all-checkbox\"\n [state]=\"isIndeterminate() ? 'indeterminate' : (isAllSelected() ? 'checked' : 'unchecked')\"></mat-pseudo-checkbox>\n <span class=\"mdc-list-item__primary-text select-all-text\">Select All</span>\n </div>\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\" \n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\" \n (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n <span class=\"tag-option\" \n [style.background]=\"getTagColor(option.value).background\" \n [style.color]=\"getTagColor(option.value).text\">\n <span class=\"tag-dot\" [style.background]=\"getTagColor(option.value).dot\"></span>\n {{ option.label }}\n </span>\n </mat-option>\n }\n\n <mat-option class=\"add-tag-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <div class=\"add-tag-container\" (click)=\"$event.stopPropagation()\">\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"add-tag-form-field\">\n <mat-label>Add new tag</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"add-tag-input\"\n [value]=\"newTagInput()\"\n (input)=\"onNewTagInputChange($any($event.target).value)\"\n (keydown.enter)=\"addNewTag()\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n <div class=\"add-tag-actions\">\n <input\n type=\"color\"\n class=\"add-tag-color-picker\"\n [value]=\"newTagColor()\"\n (input)=\"onNewTagColorChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n title=\"Select tag color\">\n <button\n mat-icon-button\n class=\"add-tag-button\"\n [disabled]=\"!canAddNewTag()\"\n (click)=\"addNewTag(); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n </mat-option>\n\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n <div \n class=\"tag-display\" \n [class.tag-display-editable]=\"isEditable()\"\n (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).text\">\n <span class=\"tag-dot\" [style.background]=\"getTagColor(tag).dot\"></span>\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n </span>\n } @else {\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).text\">\n <span class=\"tag-dot\" [style.background]=\"getTagColor(tag).dot\"></span>\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag-more\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n }\n </div>\n}\n\n", styles: [".tag-form-field{width:100%}.tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.tag-container{width:100%}.tag-display{width:100%;padding:8px 12px;min-height:30px;display:flex;flex-wrap:wrap;align-items:center;gap:4px;cursor:default}.tag-display.tag-display-editable{cursor:pointer}.tag-display.tag-display-editable:hover{background-color:#0000000a}.tag{display:inline-flex;align-items:center;gap:var(--grid-tag-dot-gap, 5px);padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);border-radius:var(--grid-pill-radius, 12px);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 500);white-space:nowrap;line-height:1.2}.tag-dot{flex:0 0 auto;width:var(--grid-tag-dot-size, 6px);height:var(--grid-tag-dot-size, 6px);border-radius:50%}.tag-more{display:inline-block;border-radius:var(--grid-pill-radius, 12px);background-color:var(--grid-surface-container-high, #f5f5f5);color:var(--grid-on-surface-variant, #49454f);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 700);font-style:italic;padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);white-space:nowrap;line-height:1.2}.drillable-value{display:flex;flex-wrap:wrap;gap:4px;align-items:center;cursor:pointer}.drillable-value .tag{text-decoration:underline}.add-option{position:sticky;position:-webkit-sticky;bottom:0;z-index:3;background:var(--grid-surface-container-high, #fff);box-shadow:0 -2px 8px -4px #00000017;border-top:1px solid var(--grid-outline-variant, #e0e0e0)}.search-option{padding:2px 4px!important;cursor:default!important;pointer-events:auto!important;width:100%!important;box-sizing:border-box!important;overflow:hidden!important}.search-option .mat-mdc-option{height:auto!important;padding:2px 4px!important;min-height:auto!important}.search-option .mat-mdc-option:hover{background:transparent!important}.search-option .mdc-list-item__primary-text{width:100%!important;max-width:100%!important;box-sizing:border-box!important;padding:0!important;margin:0!important;display:flex!important;flex-direction:column!important;gap:8px!important;opacity:1!important}.search-option .search-form-field{width:100%!important;max-width:100%!important;pointer-events:auto!important;box-sizing:border-box!important;margin:0!important}.search-option .search-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.search-option .search-form-field .mat-mdc-text-field-wrapper{padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-form-field .mat-mdc-form-field-infix{width:100%!important;max-width:100%!important;box-sizing:border-box!important;min-height:auto!important;padding:0!important}.search-option .search-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.search-option .select-all-container{padding:4px 0!important;min-height:auto!important;display:flex!important;align-items:center!important;pointer-events:auto!important;cursor:pointer!important;background:transparent!important}.search-option .select-all-container:hover{background:var(--grid-row-hover, rgba(0, 0, 0, .04))!important}.search-option .select-all-container .select-all-text{display:inline-flex!important;flex-direction:row!important;align-items:center!important;width:auto!important;max-width:none!important;gap:0!important;font-family:var(--grid-font-family, \"Poppins\")!important;font-size:var(--grid-font-size-body, 12px)!important;font-weight:500!important;color:var(--grid-on-surface, #1d1b20)!important}.search-option .select-all-container.select-all-partial .select-all-text:before,.search-option .select-all-container.select-all-partial .select-all-checkbox{opacity:.5}.tag-panel-footer{position:absolute;bottom:0;left:0;right:0;background:#fff;border-top:1px solid rgba(0,0,0,.12);padding:8px;z-index:10;box-shadow:0 -2px 4px #0000001a}.tag-panel-footer .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;pointer-events:auto}.tag-panel-footer .add-tag-form-field-wrapper{flex:1;min-width:0;position:relative}.tag-panel-footer .new-tag-input{width:100%;border:1px solid rgba(0,0,0,.38);border-radius:4px;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 12px;font-family:var(--grid-font-family, \"Poppins\")!important;box-sizing:border-box;cursor:text}.tag-panel-footer .new-tag-input:focus{border-color:var(--grid-primary, #6750a4);border-width:2px}.tag-panel-footer .add-tag-button{flex-shrink:0;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 16px!important;min-width:auto!important;pointer-events:auto!important;background-color:var(--grid-primary, #6750a4);color:#fff;border:none;border-radius:4px;cursor:pointer;font-family:var(--grid-font-family, \"Poppins\")!important}.tag-panel-footer .add-tag-button:hover:not([disabled]){opacity:.9}.tag-panel-footer .add-tag-button[disabled]{opacity:.5;cursor:not-allowed}.cdk-overlay-pane.tag-panel-overlay{position:relative;padding-bottom:60px!important}.cdk-overlay-pane.tag-panel-overlay .mat-mdc-select-panel{max-height:calc(100% - 60px)!important}.add-tag-option{position:sticky!important;background:var(--grid-surface, #fff)!important;bottom:-10px!important;z-index:10!important;padding:8px 8px 10px!important;margin-top:auto!important;margin-bottom:0!important;box-shadow:0 -2px 8px #00000026!important;border-top:1px solid rgba(0,0,0,.12)!important}.add-tag-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mat-mdc-option{min-height:auto!important;padding:0!important;height:auto!important}.add-tag-option .mat-mdc-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mdc-list-item__primary-text{width:100%!important;padding:0!important;margin:0!important}.add-tag-option .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;padding:0;margin-bottom:0}.add-tag-option .add-tag-form-field{flex:1;min-width:0}.add-tag-option .add-tag-form-field .mat-mdc-form-field-focus-overlay{background:transparent!important}.add-tag-option .add-tag-form-field .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field .mdc-notched-outline__trailing{border-color:var(--grid-outline-variant, #cac4d0)!important;border-width:1px!important}.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--grid-outline, #79747e)!important}.add-tag-option .add-tag-form-field .mdc-floating-label,.add-tag-option .add-tag-form-field label{color:var(--grid-on-surface-variant, #49454f)!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.add-tag-option .add-tag-form-field .mat-mdc-text-field-wrapper{background:transparent!important;padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-infix{min-height:auto!important;padding:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.add-tag-option .add-tag-actions{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;flex-shrink:0}.add-tag-option .add-tag-color-picker{flex-shrink:0;width:20px;height:20px;border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;padding:2px;background:transparent;box-sizing:border-box;margin:0 auto}.add-tag-option .add-tag-color-picker::-webkit-color-swatch-wrapper{padding:0}.add-tag-option .add-tag-color-picker::-webkit-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker::-moz-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker:hover{border-color:var(--grid-primary, #6750a4)}.add-tag-option .add-tag-color-picker:focus{outline:2px solid var(--grid-primary, #6750a4);outline-offset:2px}.add-tag-option .add-tag-button{flex-shrink:0;width:20px;height:20px;color:var(--grid-primary, #6750a4)!important;display:flex!important;align-items:center!important;justify-content:center!important;margin:0 auto}.add-tag-option .add-tag-button:not([disabled]){color:var(--grid-primary, #6750a4)!important}.add-tag-option .add-tag-button:not([disabled]):hover{background-color:#6750a414!important}.add-tag-option .add-tag-button[disabled]{opacity:.38;color:#00000061!important}.add-tag-option .add-tag-button mat-icon{font-size:24px;width:24px;height:24px;line-height:24px;display:flex;align-items:center;justify-content:center;margin-right:0}.tag-panel .search-option>mat-pseudo-checkbox,.tag-panel .search-option>.mat-mdc-option-pseudo-checkbox,.tag-panel .add-tag-option>mat-pseudo-checkbox,.tag-panel .add-tag-option>.mat-mdc-option-pseudo-checkbox{display:none!important}.tag-panel{min-width:200px!important}.tag-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.tag-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.tag-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}mat-option .mdc-list-item__primary-text{line-height:1.5!important;white-space:normal!important;display:flex!important;align-items:center!important}mat-option .tag-option{display:inline-flex;align-items:center;gap:var(--grid-tag-dot-gap, 5px);padding:4px 8px;border-radius:12px;font-size:var(--grid-font-size-body, 12px);font-weight:500;white-space:nowrap;line-height:1.2}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i2$3.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i2$3.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "ngmodule", type: MatPseudoCheckboxModule }, { kind: "component", type: i1$1.MatPseudoCheckbox, selector: "mat-pseudo-checkbox", inputs: ["state", "disabled", "appearance"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
8734
8756
  }
8735
8757
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: TagComponent, decorators: [{
8736
8758
  type: Component,
@@ -8744,7 +8766,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
8744
8766
  MatChipsModule,
8745
8767
  MatButtonModule,
8746
8768
  MatIconModule
8747
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"tag-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"tag-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || ''\"\n [multiple]=\"true\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"tag-panel\"\n (selectionChange)=\"onValueChange($event.value)\"\n (blur)=\"onBlur($event)\"\n (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n \n <mat-option disabled class=\"search-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n @if (isSearchable()) {\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"search-input\"\n [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n }\n <div class=\"select-all-container mat-mdc-option mdc-list-item\"\n [class.mdc-list-item--selected]=\"isAllSelected() || isIndeterminate()\"\n [class.select-all-partial]=\"isIndeterminate()\"\n (click)=\"toggleSelectAll(!isAllSelected()); $event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox select-all-checkbox\"\n [state]=\"isIndeterminate() ? 'indeterminate' : (isAllSelected() ? 'checked' : 'unchecked')\"></mat-pseudo-checkbox>\n <span class=\"mdc-list-item__primary-text select-all-text\">Select All</span>\n </div>\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\" \n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\" \n (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n <span class=\"tag-option\" \n [style.background]=\"getTagColor(option.value).background\" \n [style.color]=\"getTagColor(option.value).color\">\n {{ option.label }}\n </span>\n </mat-option>\n }\n\n <mat-option class=\"add-tag-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <div class=\"add-tag-container\" (click)=\"$event.stopPropagation()\">\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"add-tag-form-field\">\n <mat-label>Add new tag</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"add-tag-input\"\n [value]=\"newTagInput()\"\n (input)=\"onNewTagInputChange($any($event.target).value)\"\n (keydown.enter)=\"addNewTag()\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n <div class=\"add-tag-actions\">\n <input\n type=\"color\"\n class=\"add-tag-color-picker\"\n [value]=\"newTagColor()\"\n (input)=\"onNewTagColorChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n title=\"Select tag color\">\n <button\n mat-icon-button\n class=\"add-tag-button\"\n [disabled]=\"!canAddNewTag()\"\n (click)=\"addNewTag(); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n </mat-option>\n\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n <div \n class=\"tag-display\" \n [class.tag-display-editable]=\"isEditable()\"\n (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).color\">\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n </span>\n } @else {\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).color\">\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag-more\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n }\n </div>\n}\n\n", styles: [".tag-form-field{width:100%}.tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.tag-container{width:100%}.tag-display{width:100%;padding:8px 12px;min-height:30px;display:flex;flex-wrap:wrap;align-items:center;gap:4px;cursor:default}.tag-display.tag-display-editable{cursor:pointer}.tag-display.tag-display-editable:hover{background-color:#0000000a}.tag{display:inline-block;padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);border-radius:var(--grid-pill-radius, 12px);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 500);white-space:nowrap;line-height:1.2}.tag-more{display:inline-block;border-radius:var(--grid-pill-radius, 12px);background-color:var(--grid-surface-container-high, #f5f5f5);color:var(--grid-on-surface-variant, #49454f);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 700);font-style:italic;padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);white-space:nowrap;line-height:1.2}.drillable-value{display:flex;flex-wrap:wrap;gap:4px;align-items:center;cursor:pointer}.drillable-value .tag{text-decoration:underline}.add-option{position:sticky;position:-webkit-sticky;bottom:0;z-index:3;background:var(--grid-surface-container-high, #fff);box-shadow:0 -2px 8px -4px #00000017;border-top:1px solid var(--grid-outline-variant, #e0e0e0)}.search-option{padding:2px 4px!important;cursor:default!important;pointer-events:auto!important;width:100%!important;box-sizing:border-box!important;overflow:hidden!important}.search-option .mat-mdc-option{height:auto!important;padding:2px 4px!important;min-height:auto!important}.search-option .mat-mdc-option:hover{background:transparent!important}.search-option .mdc-list-item__primary-text{width:100%!important;max-width:100%!important;box-sizing:border-box!important;padding:0!important;margin:0!important;display:flex!important;flex-direction:column!important;gap:8px!important;opacity:1!important}.search-option .search-form-field{width:100%!important;max-width:100%!important;pointer-events:auto!important;box-sizing:border-box!important;margin:0!important}.search-option .search-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.search-option .search-form-field .mat-mdc-text-field-wrapper{padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-form-field .mat-mdc-form-field-infix{width:100%!important;max-width:100%!important;box-sizing:border-box!important;min-height:auto!important;padding:0!important}.search-option .search-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.search-option .select-all-container{padding:4px 0!important;min-height:auto!important;display:flex!important;align-items:center!important;pointer-events:auto!important;cursor:pointer!important;background:transparent!important}.search-option .select-all-container:hover{background:var(--grid-row-hover, rgba(0, 0, 0, .04))!important}.search-option .select-all-container .select-all-text{display:inline-flex!important;flex-direction:row!important;align-items:center!important;width:auto!important;max-width:none!important;gap:0!important;font-family:var(--grid-font-family, \"Poppins\")!important;font-size:var(--grid-font-size-body, 12px)!important;font-weight:500!important;color:var(--grid-on-surface, #1d1b20)!important}.search-option .select-all-container.select-all-partial .select-all-text:before,.search-option .select-all-container.select-all-partial .select-all-checkbox{opacity:.5}.tag-panel-footer{position:absolute;bottom:0;left:0;right:0;background:#fff;border-top:1px solid rgba(0,0,0,.12);padding:8px;z-index:10;box-shadow:0 -2px 4px #0000001a}.tag-panel-footer .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;pointer-events:auto}.tag-panel-footer .add-tag-form-field-wrapper{flex:1;min-width:0;position:relative}.tag-panel-footer .new-tag-input{width:100%;border:1px solid rgba(0,0,0,.38);border-radius:4px;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 12px;font-family:var(--grid-font-family, \"Poppins\")!important;box-sizing:border-box;cursor:text}.tag-panel-footer .new-tag-input:focus{border-color:var(--grid-primary, #6750a4);border-width:2px}.tag-panel-footer .add-tag-button{flex-shrink:0;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 16px!important;min-width:auto!important;pointer-events:auto!important;background-color:var(--grid-primary, #6750a4);color:#fff;border:none;border-radius:4px;cursor:pointer;font-family:var(--grid-font-family, \"Poppins\")!important}.tag-panel-footer .add-tag-button:hover:not([disabled]){opacity:.9}.tag-panel-footer .add-tag-button[disabled]{opacity:.5;cursor:not-allowed}.cdk-overlay-pane.tag-panel-overlay{position:relative;padding-bottom:60px!important}.cdk-overlay-pane.tag-panel-overlay .mat-mdc-select-panel{max-height:calc(100% - 60px)!important}.add-tag-option{position:sticky!important;background:var(--grid-surface, #fff)!important;bottom:-10px!important;z-index:10!important;padding:8px 8px 10px!important;margin-top:auto!important;margin-bottom:0!important;box-shadow:0 -2px 8px #00000026!important;border-top:1px solid rgba(0,0,0,.12)!important}.add-tag-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mat-mdc-option{min-height:auto!important;padding:0!important;height:auto!important}.add-tag-option .mat-mdc-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mdc-list-item__primary-text{width:100%!important;padding:0!important;margin:0!important}.add-tag-option .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;padding:0;margin-bottom:0}.add-tag-option .add-tag-form-field{flex:1;min-width:0}.add-tag-option .add-tag-form-field .mat-mdc-form-field-focus-overlay{background:transparent!important}.add-tag-option .add-tag-form-field .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field .mdc-notched-outline__trailing{border-color:var(--grid-outline-variant, #cac4d0)!important;border-width:1px!important}.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--grid-outline, #79747e)!important}.add-tag-option .add-tag-form-field .mdc-floating-label,.add-tag-option .add-tag-form-field label{color:var(--grid-on-surface-variant, #49454f)!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.add-tag-option .add-tag-form-field .mat-mdc-text-field-wrapper{background:transparent!important;padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-infix{min-height:auto!important;padding:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.add-tag-option .add-tag-actions{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;flex-shrink:0}.add-tag-option .add-tag-color-picker{flex-shrink:0;width:20px;height:20px;border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;padding:2px;background:transparent;box-sizing:border-box;margin:0 auto}.add-tag-option .add-tag-color-picker::-webkit-color-swatch-wrapper{padding:0}.add-tag-option .add-tag-color-picker::-webkit-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker::-moz-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker:hover{border-color:var(--grid-primary, #6750a4)}.add-tag-option .add-tag-color-picker:focus{outline:2px solid var(--grid-primary, #6750a4);outline-offset:2px}.add-tag-option .add-tag-button{flex-shrink:0;width:20px;height:20px;color:var(--grid-primary, #6750a4)!important;display:flex!important;align-items:center!important;justify-content:center!important;margin:0 auto}.add-tag-option .add-tag-button:not([disabled]){color:var(--grid-primary, #6750a4)!important}.add-tag-option .add-tag-button:not([disabled]):hover{background-color:#6750a414!important}.add-tag-option .add-tag-button[disabled]{opacity:.38;color:#00000061!important}.add-tag-option .add-tag-button mat-icon{font-size:24px;width:24px;height:24px;line-height:24px;display:flex;align-items:center;justify-content:center;margin-right:0}.tag-panel .search-option>mat-pseudo-checkbox,.tag-panel .search-option>.mat-mdc-option-pseudo-checkbox,.tag-panel .add-tag-option>mat-pseudo-checkbox,.tag-panel .add-tag-option>.mat-mdc-option-pseudo-checkbox{display:none!important}.tag-panel{min-width:200px!important}.tag-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.tag-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.tag-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}mat-option .mdc-list-item__primary-text{line-height:1.5!important;white-space:normal!important;display:flex!important;align-items:center!important}mat-option .tag-option{display:inline-block;padding:4px 8px;border-radius:12px;font-size:var(--grid-font-size-body, 12px);font-weight:500;white-space:nowrap;line-height:1.2}\n"] }]
8769
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"tag-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"tag-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || ''\"\n [multiple]=\"true\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"tag-panel\"\n (selectionChange)=\"onValueChange($event.value)\"\n (blur)=\"onBlur($event)\"\n (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n \n <mat-option disabled class=\"search-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n @if (isSearchable()) {\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"search-input\"\n [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n }\n <div class=\"select-all-container mat-mdc-option mdc-list-item\"\n [class.mdc-list-item--selected]=\"isAllSelected() || isIndeterminate()\"\n [class.select-all-partial]=\"isIndeterminate()\"\n (click)=\"toggleSelectAll(!isAllSelected()); $event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-pseudo-checkbox\n class=\"mat-mdc-option-pseudo-checkbox select-all-checkbox\"\n [state]=\"isIndeterminate() ? 'indeterminate' : (isAllSelected() ? 'checked' : 'unchecked')\"></mat-pseudo-checkbox>\n <span class=\"mdc-list-item__primary-text select-all-text\">Select All</span>\n </div>\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\" \n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\" \n (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n <span class=\"tag-option\" \n [style.background]=\"getTagColor(option.value).background\" \n [style.color]=\"getTagColor(option.value).text\">\n <span class=\"tag-dot\" [style.background]=\"getTagColor(option.value).dot\"></span>\n {{ option.label }}\n </span>\n </mat-option>\n }\n\n <mat-option class=\"add-tag-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <div class=\"add-tag-container\" (click)=\"$event.stopPropagation()\">\n <mat-form-field\n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"add-tag-form-field\">\n <mat-label>Add new tag</mat-label>\n <input\n matInput\n type=\"text\"\n class=\"add-tag-input\"\n [value]=\"newTagInput()\"\n (input)=\"onNewTagInputChange($any($event.target).value)\"\n (keydown.enter)=\"addNewTag()\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n <div class=\"add-tag-actions\">\n <input\n type=\"color\"\n class=\"add-tag-color-picker\"\n [value]=\"newTagColor()\"\n (input)=\"onNewTagColorChange($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\"\n title=\"Select tag color\">\n <button\n mat-icon-button\n class=\"add-tag-button\"\n [disabled]=\"!canAddNewTag()\"\n (click)=\"addNewTag(); $event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n </div>\n </mat-option>\n\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n <div \n class=\"tag-display\" \n [class.tag-display-editable]=\"isEditable()\"\n (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).text\">\n <span class=\"tag-dot\" [style.background]=\"getTagColor(tag).dot\"></span>\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n </span>\n } @else {\n @for (tag of tagDisplay().displayTags; track tag) {\n <span class=\"tag\" \n [style.background]=\"getTagColor(tag).background\" \n [style.color]=\"getTagColor(tag).text\">\n <span class=\"tag-dot\" [style.background]=\"getTagColor(tag).dot\"></span>\n {{tag}}\n </span>\n }\n @if(tagDisplay().moreCount > 0) {\n <span class=\"tag-more\">\n + {{tagDisplay().moreCount}}\n </span>\n }\n }\n </div>\n}\n\n", styles: [".tag-form-field{width:100%}.tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.tag-container{width:100%}.tag-display{width:100%;padding:8px 12px;min-height:30px;display:flex;flex-wrap:wrap;align-items:center;gap:4px;cursor:default}.tag-display.tag-display-editable{cursor:pointer}.tag-display.tag-display-editable:hover{background-color:#0000000a}.tag{display:inline-flex;align-items:center;gap:var(--grid-tag-dot-gap, 5px);padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);border-radius:var(--grid-pill-radius, 12px);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 500);white-space:nowrap;line-height:1.2}.tag-dot{flex:0 0 auto;width:var(--grid-tag-dot-size, 6px);height:var(--grid-tag-dot-size, 6px);border-radius:50%}.tag-more{display:inline-block;border-radius:var(--grid-pill-radius, 12px);background-color:var(--grid-surface-container-high, #f5f5f5);color:var(--grid-on-surface-variant, #49454f);font-size:var(--grid-pill-font-size, var(--grid-font-size-body, 12px));font-weight:var(--grid-pill-font-weight, 700);font-style:italic;padding:var(--grid-pill-padding-y, 3px) var(--grid-pill-padding-x, 10px);white-space:nowrap;line-height:1.2}.drillable-value{display:flex;flex-wrap:wrap;gap:4px;align-items:center;cursor:pointer}.drillable-value .tag{text-decoration:underline}.add-option{position:sticky;position:-webkit-sticky;bottom:0;z-index:3;background:var(--grid-surface-container-high, #fff);box-shadow:0 -2px 8px -4px #00000017;border-top:1px solid var(--grid-outline-variant, #e0e0e0)}.search-option{padding:2px 4px!important;cursor:default!important;pointer-events:auto!important;width:100%!important;box-sizing:border-box!important;overflow:hidden!important}.search-option .mat-mdc-option{height:auto!important;padding:2px 4px!important;min-height:auto!important}.search-option .mat-mdc-option:hover{background:transparent!important}.search-option .mdc-list-item__primary-text{width:100%!important;max-width:100%!important;box-sizing:border-box!important;padding:0!important;margin:0!important;display:flex!important;flex-direction:column!important;gap:8px!important;opacity:1!important}.search-option .search-form-field{width:100%!important;max-width:100%!important;pointer-events:auto!important;box-sizing:border-box!important;margin:0!important}.search-option .search-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.search-option .search-form-field .mat-mdc-text-field-wrapper{padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-form-field .mat-mdc-form-field-infix{width:100%!important;max-width:100%!important;box-sizing:border-box!important;min-height:auto!important;padding:0!important}.search-option .search-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.search-option .search-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.search-option .select-all-container{padding:4px 0!important;min-height:auto!important;display:flex!important;align-items:center!important;pointer-events:auto!important;cursor:pointer!important;background:transparent!important}.search-option .select-all-container:hover{background:var(--grid-row-hover, rgba(0, 0, 0, .04))!important}.search-option .select-all-container .select-all-text{display:inline-flex!important;flex-direction:row!important;align-items:center!important;width:auto!important;max-width:none!important;gap:0!important;font-family:var(--grid-font-family, \"Poppins\")!important;font-size:var(--grid-font-size-body, 12px)!important;font-weight:500!important;color:var(--grid-on-surface, #1d1b20)!important}.search-option .select-all-container.select-all-partial .select-all-text:before,.search-option .select-all-container.select-all-partial .select-all-checkbox{opacity:.5}.tag-panel-footer{position:absolute;bottom:0;left:0;right:0;background:#fff;border-top:1px solid rgba(0,0,0,.12);padding:8px;z-index:10;box-shadow:0 -2px 4px #0000001a}.tag-panel-footer .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;pointer-events:auto}.tag-panel-footer .add-tag-form-field-wrapper{flex:1;min-width:0;position:relative}.tag-panel-footer .new-tag-input{width:100%;border:1px solid rgba(0,0,0,.38);border-radius:4px;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 12px;font-family:var(--grid-font-family, \"Poppins\")!important;box-sizing:border-box;cursor:text}.tag-panel-footer .new-tag-input:focus{border-color:var(--grid-primary, #6750a4);border-width:2px}.tag-panel-footer .add-tag-button{flex-shrink:0;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 16px!important;min-width:auto!important;pointer-events:auto!important;background-color:var(--grid-primary, #6750a4);color:#fff;border:none;border-radius:4px;cursor:pointer;font-family:var(--grid-font-family, \"Poppins\")!important}.tag-panel-footer .add-tag-button:hover:not([disabled]){opacity:.9}.tag-panel-footer .add-tag-button[disabled]{opacity:.5;cursor:not-allowed}.cdk-overlay-pane.tag-panel-overlay{position:relative;padding-bottom:60px!important}.cdk-overlay-pane.tag-panel-overlay .mat-mdc-select-panel{max-height:calc(100% - 60px)!important}.add-tag-option{position:sticky!important;background:var(--grid-surface, #fff)!important;bottom:-10px!important;z-index:10!important;padding:8px 8px 10px!important;margin-top:auto!important;margin-bottom:0!important;box-shadow:0 -2px 8px #00000026!important;border-top:1px solid rgba(0,0,0,.12)!important}.add-tag-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mat-mdc-option{min-height:auto!important;padding:0!important;height:auto!important}.add-tag-option .mat-mdc-option:hover{background:var(--grid-surface, #fff)!important}.add-tag-option .mdc-list-item__primary-text{width:100%!important;padding:0!important;margin:0!important}.add-tag-option .add-tag-container{display:flex;align-items:center;gap:8px;width:100%;padding:0;margin-bottom:0}.add-tag-option .add-tag-form-field{flex:1;min-width:0}.add-tag-option .add-tag-form-field .mat-mdc-form-field-focus-overlay{background:transparent!important}.add-tag-option .add-tag-form-field .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field .mdc-notched-outline__trailing{border-color:var(--grid-outline-variant, #cac4d0)!important;border-width:1px!important}.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__leading,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__notch,.add-tag-option .add-tag-form-field.mat-focused .mdc-notched-outline__trailing{border-color:var(--grid-outline, #79747e)!important}.add-tag-option .add-tag-form-field .mdc-floating-label,.add-tag-option .add-tag-form-field label{color:var(--grid-on-surface-variant, #49454f)!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.add-tag-option .add-tag-form-field .mat-mdc-text-field-wrapper{background:transparent!important;padding-bottom:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-infix{min-height:auto!important;padding:0!important;width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-form-field .mat-mdc-form-field-flex{width:100%!important;max-width:100%!important;box-sizing:border-box!important}.add-tag-option .add-tag-input{width:100%;border:none;outline:none;background:transparent;font-size:var(--grid-font-size-body, 12px)!important;padding:8px 0}.add-tag-option .add-tag-actions{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;flex-shrink:0}.add-tag-option .add-tag-color-picker{flex-shrink:0;width:20px;height:20px;border:1px solid rgba(0,0,0,.12);border-radius:4px;cursor:pointer;padding:2px;background:transparent;box-sizing:border-box;margin:0 auto}.add-tag-option .add-tag-color-picker::-webkit-color-swatch-wrapper{padding:0}.add-tag-option .add-tag-color-picker::-webkit-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker::-moz-color-swatch{border:none;border-radius:2px}.add-tag-option .add-tag-color-picker:hover{border-color:var(--grid-primary, #6750a4)}.add-tag-option .add-tag-color-picker:focus{outline:2px solid var(--grid-primary, #6750a4);outline-offset:2px}.add-tag-option .add-tag-button{flex-shrink:0;width:20px;height:20px;color:var(--grid-primary, #6750a4)!important;display:flex!important;align-items:center!important;justify-content:center!important;margin:0 auto}.add-tag-option .add-tag-button:not([disabled]){color:var(--grid-primary, #6750a4)!important}.add-tag-option .add-tag-button:not([disabled]):hover{background-color:#6750a414!important}.add-tag-option .add-tag-button[disabled]{opacity:.38;color:#00000061!important}.add-tag-option .add-tag-button mat-icon{font-size:24px;width:24px;height:24px;line-height:24px;display:flex;align-items:center;justify-content:center;margin-right:0}.tag-panel .search-option>mat-pseudo-checkbox,.tag-panel .search-option>.mat-mdc-option-pseudo-checkbox,.tag-panel .add-tag-option>mat-pseudo-checkbox,.tag-panel .add-tag-option>.mat-mdc-option-pseudo-checkbox{display:none!important}.tag-panel{min-width:200px!important}.tag-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.tag-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.tag-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}mat-option .mdc-list-item__primary-text{line-height:1.5!important;white-space:normal!important;display:flex!important;align-items:center!important}mat-option .tag-option{display:inline-flex;align-items:center;gap:var(--grid-tag-dot-gap, 5px);padding:4px 8px;border-radius:12px;font-size:var(--grid-font-size-body, 12px);font-weight:500;white-space:nowrap;line-height:1.2}\n"] }]
8748
8770
  }], ctorParameters: () => [], propDecorators: { selectContainer: [{
8749
8771
  type: ViewChild,
8750
8772
  args: ['selectContainer', { static: false }]
@@ -12050,7 +12072,17 @@ class ColumnDesignPanelComponent {
12050
12072
  });
12051
12073
  }
12052
12074
  getValue(key) {
12053
- return this.field()?.[key] ?? null;
12075
+ const value = this.field()?.[key] ?? null;
12076
+ // A date pattern is stored in whatever casing wrote it — the data model
12077
+ // uppercases ('DD-MM-YYYY'), older UIs wrote lowercase — while the option
12078
+ // values are token-cased. Match on the canonical form so the select shows
12079
+ // the pattern in force instead of reading as unset.
12080
+ if (key === 'date_format' && typeof value === 'string' && value) {
12081
+ return String(this.field()?.datatype).toLowerCase() === 'datetime'
12082
+ ? normalizeDateTimeFormat(value)
12083
+ : normalizeDateFormat(value);
12084
+ }
12085
+ return value;
12054
12086
  }
12055
12087
  // Checkbox state with a config-level default (e.g. `editable` reads as
12056
12088
  // checked until explicitly turned off).
@@ -12499,6 +12531,7 @@ class EruGridComponent {
12499
12531
  family: config?.header_font_family || '',
12500
12532
  size: config?.header_font_size ?? 0,
12501
12533
  bold: config?.header_font_bold ?? false,
12534
+ color: config?.header_font_color || '',
12502
12535
  },
12503
12536
  border: [{
12504
12537
  type: config?.header_border_type || '',
@@ -12516,6 +12549,7 @@ class EruGridComponent {
12516
12549
  family: config?.data_font_family || '',
12517
12550
  size: config?.data_font_size ?? 0,
12518
12551
  bold: config?.data_font_bold ?? false,
12552
+ color: config?.data_font_color || '',
12519
12553
  },
12520
12554
  border: [{
12521
12555
  type: config?.data_border_type || '',
@@ -13933,6 +13967,24 @@ class EruGridComponent {
13933
13967
  if (v !== undefined && v !== null && v !== '')
13934
13968
  patch[k] = v;
13935
13969
  }
13970
+ // setColumns() stores the canonical datatype ('r_status' -> 'status'), so a
13971
+ // patch carrying the raw alias never compares equal to what was just
13972
+ // written: the resolve effect saw `changed` on every pass and re-applied
13973
+ // for ever, hanging the page the moment an aliased field (Record Status)
13974
+ // was mapped. Canonicalise here so the patch is idempotent.
13975
+ if (patch.datatype !== undefined) {
13976
+ patch.datatype = normalizeDatatype(patch.datatype);
13977
+ }
13978
+ // The data model uppercases the pattern on save ('DD-MM-YYYY'), while the
13979
+ // canonical token form is 'dd-MM-yyyy' — lowercase `mm` means minutes. The
13980
+ // renderers normalise on read, but the column-design panel matches the raw
13981
+ // value against its option list, so an inherited pattern arrived as a blank
13982
+ // select. Canonicalise once here and every consumer agrees.
13983
+ if (typeof patch.date_format === 'string') {
13984
+ patch.date_format = String(meta?.datatype).toLowerCase() === 'datetime'
13985
+ ? normalizeDateTimeFormat(patch.date_format)
13986
+ : normalizeDateFormat(patch.date_format);
13987
+ }
13936
13988
  return patch;
13937
13989
  }
13938
13990
  /** Get the field name used for grouping */
@@ -14621,7 +14673,7 @@ class EruGridComponent {
14621
14673
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EruGridComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
14622
14674
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: EruGridComponent, isStandalone: true, selector: "eru-grid", inputs: { gridConfig: "gridConfig", boardCardTemplate: "boardCardTemplate", personCardTemplate: "personCardTemplate", boardCardHeight: "boardCardHeight", boardCardGap: "boardCardGap", boardCardPadding: "boardCardPadding" }, outputs: { rowSelect: "rowSelect", actionClick: "actionClick" }, providers: [EruGridStore, EruGridService,
14623
14675
  ...MATERIAL_PROVIDERS
14624
- ], viewQueries: [{ propertyName: "rowContainer", first: true, predicate: ["rowContainer"], descendants: true }, { propertyName: "headerScroller", first: true, predicate: ["headerScroller"], descendants: true, read: ElementRef }, { propertyName: "gtScroller", first: true, predicate: ["gtScroller"], descendants: true, read: ElementRef }, { propertyName: "viewport", first: true, predicate: ["vp"], descendants: true }, { propertyName: "groupsViewport", first: true, predicate: ["groupsViewport"], descendants: true }, { propertyName: "groupsScrollContainerEl", first: true, predicate: ["groupsScrollContainer"], descendants: true }, { propertyName: "allViewports", predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "headerScrollers", predicate: ["headerScroller"], descendants: true }], ngImport: i0, template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\ncurrentPivotScrollIndex {{currentPivotScrollIndex()}} |\nfirstDataRowIndex {{firstDataRowIndex()}} |\nfirstTr {{firstTr}} |\nmaxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode() && !isBoardMode()\" [class.board-mode-host]=\"isBoardMode()\">\n <eru-column-design-panel></eru-column-design-panel>\n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container>\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n\n\n <div class=\"pivot-single-table\"\n style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table>\n </div>\n }\n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport #vp [itemSize]=\"dataRowHeight()\" class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\" (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\" style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n\n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\" class=\"pivot-row\" [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) {\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.pivot-repeated-value]=\"isRepeatedDimensionValue(i, column.name)\"\n [class.pivot-group-start]=\"isPivotGroupStart(i, column.name)\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [personCardTemplate]=\"personCardTemplate\" [class.aggregation]=\"!!column.aggregationFunction\" [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\" [value]=\"pivotRow[column.name]\"\n [column]=\"column\" [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\"\n [isEditable]=\"isEditable()\" [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\"\n [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n } @else {\n <td [style.height.px]=\"dataRowHeight()\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\" [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n\n </table>\n </div>\n }\n\n\n </div>\n </div>\n </ng-container>\n } @else if (isBoardMode()) {\n <!-- Board Mode Template -->\n <div class=\"board-view-container\">\n @if(showSortBar()) {\n <div class=\"board-sort-bar\">\n <span class=\"board-sort-label\">Sort by:</span>\n @for (entry of gridStore.sortColumns(); track getFieldName(entry)) {\n <span class=\"board-sort-chip board-sort-chip-active\">\n <span class=\"board-sort-chip-label\">{{getColumnLabel(entry)}}</span>\n <span class=\"board-sort-chip-arrow\" (click)=\"onBoardSortChipToggle($event, entry)\">\n @if(!entry.startsWith('-')) { \u25B2 } @else { \u25BC }\n </span>\n @if(gridStore.sortColumns().length > 1) {\n <span class=\"board-sort-chip-priority\">{{getSortPriority(getFieldName(entry))}}</span>\n }\n <span class=\"board-sort-chip-remove\" (click)=\"onBoardSortChipRemove($event, entry)\">\u2715</span>\n </span>\n }\n <button class=\"board-sort-add-btn\" [matMenuTriggerFor]=\"sortFieldMenu\">\n <mat-icon class=\"board-sort-add-icon\">add</mat-icon> Add field\n </button>\n <mat-menu #sortFieldMenu=\"matMenu\" class=\"board-sort-menu\">\n @for (column of columns(); track column.name) {\n <button mat-menu-item (click)=\"onBoardSortFieldSelect(column)\"\n [disabled]=\"getSortDirection(column.name) !== null\">\n @if(getSortDirection(column.name) !== null) {\n <mat-icon>check</mat-icon>\n } @else {\n <mat-icon></mat-icon>\n }\n {{column.label}}\n </button>\n }\n </mat-menu>\n @if(gridStore.sortColumns().length > 0) {\n <button class=\"board-sort-clear\" (click)=\"onBoardSortClear()\">\u2715 Clear</button>\n }\n </div>\n }\n <div class=\"board-columns-wrapper\" [class.board-columns-nowrap]=\"!boardWrapColumns()\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\" [class.board-column-accented]=\"!!boardGroupColor(group)\"\n [style.--board-group-color]=\"boardGroupColor(group)\">\n @if (showBoardColumnHeader()) {\n <div class=\"column-header\">\n <!-- Render the group value through the same read-only cell renderer a\n data cell uses, so the grouped field's datatype formats itself\n (status/tag pills, dates, numbers) instead of printing raw text. -->\n @if (groupByColumn(); as gcol) {\n <span class=\"column-header-title column-header-title-cell\">\n <data-cell\n [eruGridStore]=\"gridStore\"\n [column]=\"gcol\"\n [columnDatatype]=\"gcol.datatype\"\n [columnName]=\"gcol.name\"\n [value]=\"group.title\"\n [id]=\"'board-group-' + group.id\"\n [fieldSize]=\"0\"\n [isEditable]=\"false\"\n [mode]=\"'board-group-header'\">\n </data-cell>\n </span>\n } @else {\n <span class=\"column-header-title\">{{ group.title }}</span>\n }\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n }\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"boardCardSlot\" class=\"board-column-body\"\n [style.height.px]=\"boardColumnBodyHeight(group)\"\n (scrolledIndexChange)=\"onBoardScrolledIndexChange($event, group)\">\n <div\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); templateCacheSize: 0\"\n class=\"board-card-container\"\n [class.selected]=\"isBoardCardActive(row)\"\n [class.show-row-lines]=\"showRowLines()\"\n [style.height.px]=\"boardCardOuterHeight\"\n [style.padding.px]=\"boardCardPadding\"\n [style.marginBottom.px]=\"boardCardGap\"\n [style.cursor]=\"cursorOnHover() || null\"\n (click)=\"emitRowSelect(row, 'board', group)\">\n <!-- Custom template when consumer provides boardCardTemplate; default card otherwise -->\n <ng-container\n *ngTemplateOutlet=\"boardCardTemplate ?? defaultBoardCard;\n context: { $implicit: row, columns: visibleBoardFields(), group: group }\">\n </ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n @if (group.isLoading) {\n <div class=\"board-ghost-card\">\n <div class=\"board-ghost-line\"></div>\n <div class=\"board-ghost-line board-ghost-line--short\"></div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n\n <!-- Table Mode Template -->\n <ng-template #excelDownloadIcon>\n <svg class=\"excel-download-icon\" title=\"Download Excel\" (click)=\"onExcelDownloadClick($event)\"\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"24px\" height=\"24px\">\n <path fill=\"#169154\" d=\"M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z\" />\n <path fill=\"#18482a\" d=\"M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z\" />\n <path fill=\"#0c8045\" d=\"M14 15.003H29V24.005000000000003H14z\" />\n <path fill=\"#17472a\" d=\"M14 24.005H29V33.055H14z\" />\n <g>\n <path fill=\"#29c27f\" d=\"M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z\" />\n <path fill=\"#27663f\" d=\"M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z\" />\n <path fill=\"#19ac65\" d=\"M29 15.003H44V24.005000000000003H29z\" />\n <path fill=\"#129652\" d=\"M29 24.005H44V33.055H29z\" />\n </g>\n <path fill=\"#0c7238\"\n d=\"M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z\" />\n <path fill=\"#fff\"\n d=\"M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z\" />\n </svg>\n </ng-template>\n @if(showExcelDownload() && !showGroupBar()) {\n <div class=\"excel-download-bar\">\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n </div>\n }\n <!-- Scrollable groups container \u2014 plain iteration avoids CDK fixed-height estimation errors -->\n <div #groupsScrollContainer class=\"groups-scroll-container\" (scroll)=\"onGroupsViewportScroll($event)\">\n\n @for (group of groups(); track trackByGroupFn($index, group); let i = $index) {\n <div class=\"group-container\"\n [attr.data-group-id]=\"group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id\">\n <!-- Combined sticky header with group info and table -->\n <div style=\"\n background:var(--grid-surface);\n position: sticky;\n top: 0;\n z-index: 115;\n \">\n @if(showGroupBar()) {\n <div class=\"group-header-row\">\n <div class=\"custom-collapse-header\" (click)=\"toggleGroupCollapse(group.id)\">\n <span class=\"collapse-arrow\" [ngClass]=\"{\n 'rotate-arrow': group.isExpanded,\n }\">\u25BC</span>\n <span class=\"f-12\">\n {{ group?.title || \"\" }}\n {{ group?.currentLoadedRows || 0 }} -\n {{ group?.totalRowCount || 0 }} rows...</span>\n @if(groupByField() && isSortable()) {\n <span class=\"group-sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'asc'\"\n (click)=\"onGroupSortToggle($event, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\"\n [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'desc'\"\n (click)=\"onGroupSortToggle($event, 'desc')\"></span>\n </span>\n </span>\n }\n </div>\n @if(i === 0 && showExcelDownload()) {\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n }\n </div>\n }\n\n @if(freezeHeader() && (group.isExpanded || !showGroupBar())) {\n <div #headerScroller class=\"header-shell\" [attr.data-group-id]=\"'header-shell-' + group.id\"\n [style]=\"'--table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <table class=\"eru-grid-table\" [class.freeze-header]=\"freezeHeader()\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n <!-- Grand Total row after sticky header (position: before) - only for first group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' && hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after sticky header (position: before) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'before' && hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n </table>\n </div>\n }\n </div>\n @if(group.isExpanded || !showGroupBar()) {\n <ng-container>\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"dataRowHeight()\" class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event, group)\" (scroll)=\"onTableBodyScroll($event)\"\n [style]=\"'--table-height: ' + getGroupContentHeight(group.id) + 'px; --table-min-height: ' + getGroupContentHeight(group.id) + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <div class=\"table-wrapper\">\n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\"\n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n @if(!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n }\n <!-- Grand Total row after normal header (position: before) - only for first group -->\n @if(!freezeHeader() && enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' &&\n hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after normal header (position: before) -->\n @if(!freezeHeader() && enableColumnSubtotals() && subtotalPositionColumn() === 'before' &&\n hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n <tbody>\n @if (columns(); as columnsList) {\n <!-- <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr> -->\n <!-- @if(getRowsForGroup(group.id).length > 0 && group.isExpanded) { -->\n <!-- *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id)(); \n trackBy: trackByRowFn; \n let i = index\" -->\n <!-- @for(row of getRowsForGroupSignal(group.id)(); track trackByRowFn($index, row); let i = $index) { -->\n <ng-container\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); trackBy: trackByRowFn; let i = index\">\n <tr class=\"row-item\" [attr.data-row-id]=\"i\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" (click)=\"emitRowSelect(row, 'table', group)\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input type=\"checkbox\" [checked]=\"isRowSelected(row?.entity_id)\"\n (change)=\"toggleRowSelection($event, row)\">\n </td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\" (click)=\"toggleRowExpand(row, i, $event)\">\n <mat-icon class=\"row-expand-icon\" [class.expanded]=\"isRowExpanded(row, i)\">chevron_right</mat-icon>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td #cell [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\"\n [matTooltipClass]=\"'error-message'\" [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\">\n <div class=\"cell-content\">\n <data-cell #datacell [personCardTemplate]=\"personCardTemplate\" [td]=cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\" [value]=\"(row?.['entity_data']?.[column.name] ?? row?.[column.name]) || ''\" [column]=\"column\"\n [mode]=\"mode()\" [isEditable]=\"isEditable() && column.editable !== false && column.editable !== 'false'\" [drillable]=\"column.enableDrilldown || false\"\n [id]=\"i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n </tr>\n @if(hasHiddenColumns() && isRowExpanded(row, i)) {\n <tr class=\"row-detail\">\n <td class=\"row-detail-cell\" [attr.colspan]=\"rowDetailColspan()\">\n <div class=\"row-detail-grid\">\n @for (hiddenCol of hiddenColumns(); track trackByColumnFn($index, hiddenCol)) {\n <div class=\"row-detail-field\">\n <span class=\"row-detail-label\">{{hiddenCol.label}}</span>\n <div class=\"row-detail-value\">\n <data-cell [fieldSize]=\"hiddenCol.field_size\" [columnDatatype]=\"hiddenCol.datatype\"\n [columnName]=\"hiddenCol.name\" [value]=\"(row?.['entity_data']?.[hiddenCol.name] ?? row?.[hiddenCol.name]) || ''\"\n [column]=\"hiddenCol\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [drillable]=\"hiddenCol.enableDrilldown || false\"\n [id]=\"'detail_' + i + '_' + hiddenCol.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-container>\n <!-- } -->\n <!-- } -->\n @if(group.isLoading && (group.isExpanded || !showGroupBar())) {\n @for(i of [].constructor(ghostRows()); let j = $index; track j) {\n <tr class=\"ghost-loading-row\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n </tr>\n }\n }\n <!-- <tr\n *ngIf=\"getRowsForGroup(group.id).length === 0 && !group.isExpanded\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr> -->\n <!-- Subtotal row at end of group (position: after) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'after' && hasSubtotalData(group)) {\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n }\n <!-- Grand Total row at end of group (position: after) - only for last group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'after' && hasGrandTotalData() && i ===\n groups().length - 1) {\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n }\n }\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container>\n }\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Pivot Table Header Template -->\n<ng-template #pivotTableHead>\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n @if (hasNestedHeaders()) {\n <ng-container>\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th [attr.colspan]=\"header.colspan\" [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"isResizablePivotHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header) || $any(header)\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\" [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\" [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor($any(header))\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n\n <data-cell [fieldSize]=\"header.field_size\" [columnDatatype]=\"header.dataType\" [columnName]=\"header.name\"\n [value]=\"header.label\" [column]=\"header\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\" [eruGridStore]=\"gridStore\" [row]=\"header\">\n </data-cell>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader($any(header)) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, $any(header))\">tune</mat-icon>\n }\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\"\n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\" [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\" [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor(column)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto;padding: 8px 6px\">\n <!-- Label and control laid out as a row: the label truncates, the\n control keeps its place. Left as a bare text node the long\n aggregation labels pushed the icon past the cell edge, where\n `overflow: hidden` clipped it out of sight entirely. -->\n <div class=\"pivot-header-content\">\n <!-- Deliberately not `.column-label`: that class carries the\n wrap-headers rule, which broke these labels onto one word per\n line. This header truncates, as it did before. -->\n <span class=\"pivot-header-label\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader(column) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n </div>\n </th>\n }\n </tr>\n </ng-container>\n }\n\n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n <tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\" [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"50\" [attr.xx]=\"i\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\" [column]=\"column\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n }\n </tbody>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Action column cell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One template for both column positions. With no `config.actions` set it\n falls back to the single more_horiz icon the column has always shown, so\n grids that only listen to the store's actionClick signal keep working.\n Context: { $implicit: Row, mode: 'table' | 'board', group?: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #actionCell let-row let-mode=\"mode\" let-group=\"group\">\n @if(!hasConfiguredActions()) {\n <mat-icon (click)=\"onActionClick($event, row, undefined, mode || 'table', group)\">more_horiz</mat-icon>\n } @else if(actionDisplayType() === 'kebab') {\n @if(visibleActionsFor(row).length > 0) {\n <mat-icon class=\"action-kebab\" [matMenuTriggerFor]=\"rowActionMenu\"\n [matMenuTriggerData]=\"{ row: row, mode: mode || 'table', group: group }\"\n (click)=\"$event.stopPropagation()\">more_vert</mat-icon>\n }\n } @else {\n <div class=\"action-icons\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <mat-icon class=\"action-icon\" [matTooltip]=\"action.action_name\" matTooltipPosition=\"above\"\n (click)=\"onActionClick($event, row, action, mode || 'table', group)\">{{action.action_icon || 'play_arrow'}}</mat-icon>\n }\n </div>\n }\n</ng-template>\n\n<!-- Kebab menu shared by every row; the row is passed through matMenuTriggerData. -->\n<mat-menu #rowActionMenu=\"matMenu\" class=\"eru-grid-action-menu\">\n <ng-template matMenuContent let-row=\"row\" let-mode=\"mode\" let-group=\"group\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <button mat-menu-item (click)=\"onActionClick($event, row, action, mode || 'table', group)\">\n <mat-icon>{{action.action_icon || 'play_arrow'}}</mat-icon>\n <span>{{action.action_name}}</span>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #tableColGroup>\n <colgroup>\n @if(gridStore.configuration().config.allowSelection) {\n <col style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n }\n @if(shouldShowActionColumn('before')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n @if(hasHiddenColumns()) {\n <col style=\"width: 40px !important; min-width: 40px !important; max-width: 40px !important;\">\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n @if(shouldShowActionColumn('after')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n </colgroup>\n</ng-template>\n\n\n<ng-template #tableHeader>\n\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n <tr>\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column column-header table-column-header\">\n <input type=\"checkbox\" [checked]=\"isAllGroupsSelected()\" (change)=\"toggleAllGroups($event)\">\n </th>\n }\n @if(shouldShowActionColumn('before')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n @if(hasHiddenColumns()) {\n <th class=\"row-expand-toggle column-header table-column-header\"></th>\n }\n @for (column of visibleColumns(); track trackByColumnFn(i, column); let i = $index) {\n <th [style.width.px]=\"column.field_size\" [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\" [index]=\"i\"\n [columnDraggable]=\"gridStore.isFeatureEnabled('columnReorderable') ? i : null\"\n [style.minWidth.px]=\"column.field_size\" class=\"column-header table-column-header\"\n [class.sortable-header]=\"isSortable()\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === column.name\"\n [class.sort-asc]=\"isSortable() && getSortDirection(column.name) === 'asc'\"\n [class.sort-desc]=\"isSortable() && getSortDirection(column.name) === 'desc'\">\n @if(gridStore.isFeatureEnabled('columnReorderable')) {\n <div class=\"column-drag-handle\"></div>\n }\n <span class=\"column-label\" [title]=\"column.tool_tip || column.description || ''\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\" title=\"Edit column\" (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n @if(isSortable()) {\n <span class=\"sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'asc'\"\n (click)=\"onSortColumn($event, column, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'desc'\"\n (click)=\"onSortColumn($event, column, 'desc')\"></span>\n </span>\n @if(getSortPriority(column.name) !== null && gridStore.sortColumns().length > 1) {\n <span class=\"sort-priority\">{{getSortPriority(column.name)}}</span>\n }\n </span>\n }\n </th>\n }\n @if(shouldShowActionColumn('after')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n </tr>\n </thead>\n</ng-template>\n\n<!-- Table Subtotal Row Template -->\n<ng-template #tableSubtotal let-group=\"group\">\n <tr class=\"subtotal-row\" [class.subtotal-bold]=\"subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"subTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"subtotal-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getSubtotalValue(group, column.name) === null) {\n <span class=\"subtotal-label\">{{subtotalLabel()}}</span>\n } @else {\n @if(getSubtotalValue(group, column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getSubtotalValue(group, column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'subtotal_' + group.id + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"group.subtotal\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- Table Grand Total Row Template -->\n<ng-template #tableGrandTotal>\n <tr class=\"grand-total-row\" [class.grand-total-bold]=\"grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"grandTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"grand-total-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getGrandTotalValue(column.name) === null) {\n <span class=\"grand-total-label\">Grand Total</span>\n } @else {\n @if(getGrandTotalValue(column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getGrandTotalValue(column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'grandtotal_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"gridStore.rowGrandTotal()\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Default board card template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Used when no boardCardTemplate is passed to <eru-grid>.\n Context: { $implicit: Row, columns: Field[], group: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #defaultBoardCard let-row let-columns=\"columns\" let-group=\"group\">\n <mat-card class=\"board-card\">\n <mat-card-content>\n @for (column of columns; track column.name) {\n @if ((row?.entity_data?.[column.name] ?? row?.[column.name]) !== undefined) {\n <div class=\"board-card-field\">\n <span class=\"board-field-label\">{{ column.label }}</span>\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [column]=\"column\"\n [value]=\"row?.entity_data?.[column.name] ?? row?.[column.name]\"\n [id]=\"row?.entity_id + '_' + column.name\"\n [eruGridStore]=\"gridStore\"\n [mode]=\"'board'\"\n [row]=\"row\">\n </data-cell>\n </div>\n }\n }\n </mat-card-content>\n <mat-card-actions align=\"end\">\n <button mat-icon-button (click)=\"onActionClick($event, row)\">\n <mat-icon>more_horiz</mat-icon>\n </button>\n </mat-card-actions>\n </mat-card>\n</ng-template>", styles: ["@charset \"UTF-8\";:root{--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6}:host,eru-grid{display:block!important;width:100%;height:100%;flex:1 1 0%;max-height:var(--grid-height, none);min-height:var(--grid-min-height, 120px);font-family:var(--grid-font-family);--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15);--grid-row-hover: var(--grid-surface-variant);--grid-row-selected: var(--grid-surface-container-high);--grid-zebra-odd: transparent;--grid-zebra-even: transparent;--grid-focus-ring: var(--grid-primary);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: var(--grid-font-size-caption);--grid-header-padding-x: 8px;--grid-header-padding-y: 12px;--grid-font-feature-numeric: normal;--grid-cell-padding-x: var(--grid-spacing-xs);--grid-cell-padding-y: var(--grid-spacing-xxs);--grid-tint-subtle: rgba(0, 0, 0, .025);--grid-tint-soft: rgba(0, 0, 0, .045);--grid-tint-strong: rgba(0, 0, 0, .08);--grid-radius-outer: 0;--grid-shadow-outer: none;--grid-divider-color: var(--grid-outline-variant);--grid-divider-width: 1px;--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-pill-radius: 999px;--grid-pill-padding-y: 3px;--grid-pill-padding-x: 10px;--grid-pill-font-size: 11px;--grid-pill-font-weight: 500;--grid-priority-dot-size: 8px;--grid-avatar-size: 24px;--grid-avatar-font-size: 10px;--grid-avatar-font-weight: 600;border-radius:var(--grid-radius-outer);box-shadow:var(--grid-shadow-outer)}eru-grid[data-preset=default]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .06em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-soft);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=modern]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: 13px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 16px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 12px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px}eru-grid[data-preset=compact]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 11px;--grid-header-padding-y: 4px;--grid-header-padding-x: 8px;--grid-cell-padding-y: 3px;--grid-cell-padding-x: 8px;--grid-font-size-body: 11px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 1px;--grid-pill-padding-x: 6px;--grid-pill-font-size: 10px}eru-grid[data-preset=bold]{--grid-header-bg: var(--grid-surface-container-high);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 700;--grid-header-text-transform: none;--grid-header-font-size: 13px;--grid-header-padding-y: 14px;--grid-header-padding-x: 12px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 12px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-strong);--grid-divider-width: 1px;--grid-radius-outer: 2px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=financial]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .08em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-zebra-odd: transparent;--grid-zebra-even: var(--grid-tint-subtle);--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=elevated]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 12px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 14px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 16px;--grid-shadow-outer: 0 1px 3px rgba(0, 0, 0, .06), 0 10px 28px rgba(0, 0, 0, .07);--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px;overflow:hidden}.group-container{padding-bottom:8px}.column-header.design-clickable .design-edit-icon{font-size:16px;width:16px;height:16px;margin-left:4px;opacity:.45;vertical-align:middle;cursor:pointer}.column-header.design-clickable:hover .design-edit-icon,.column-header.design-clickable .design-edit-icon:hover{opacity:1}.column-header.design-selected{background-color:var(--grid-primary-light, rgba(63, 81, 181, .12))}.pivot-column-header .pivot-header-content{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}.pivot-column-header .pivot-header-content .pivot-header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.pivot-column-header .pivot-header-content .design-edit-icon,.pivot-column-header .header-content .design-edit-icon{flex:0 0 auto}.pivot-column-header .header-content data-cell,.pivot-column-header .header-content data-cell *{color:inherit!important}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-min-height, 120px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);font-family:var(--grid-font-family)}.viewport{height:100%;min-height:300px;overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.groups-viewport{height:100%;min-height:300px}.groups-scroll-container{max-height:var(--grid-height, 600px);overflow-y:auto;overflow-x:hidden}.table-viewport{background-color:var(--grid-surface);height:var(--table-height, auto);min-height:var(--table-min-height, 100px);overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th{background-color:var(--grid-header-bg, var(--grid-surface-container))}thead.eru-wrap-headers th{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;height:auto}thead.eru-wrap-headers th .column-label,thead.eru-wrap-headers th .header-label{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;word-break:break-word;overflow-wrap:anywhere}.eru-grid-table tbody td{background-color:transparent}.eru-grid-table thead{background-color:var(--grid-header-bg, var(--grid-surface-container));transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{position:sticky!important;top:0!important;z-index:100!important}.eru-grid-table thead th{background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface));font-family:var(--grid-font-family);font-weight:var(--grid-header-font-weight);font-size:var(--grid-header-font-size)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.action-column{text-align:center;background-color:var(--grid-surface-container)}.action-column mat-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);cursor:pointer}.action-column mat-icon:hover{color:var(--grid-primary)}.action-column .action-icons{display:flex;align-items:center;justify-content:center;gap:6px;overflow-x:auto;scrollbar-width:none}.action-column .action-icons::-webkit-scrollbar{display:none}.action-column .action-icon{flex:0 0 auto}.eru-grid-action-menu .mat-mdc-menu-item mat-icon{margin-right:8px;font-size:18px;width:18px;height:18px;line-height:18px;color:var(--grid-on-surface-variant)}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{background-color:var(--grid-surface);transition:background-color .15s ease}.row-item:nth-child(odd){background-color:var(--grid-zebra-odd, var(--grid-surface))}.row-item:nth-child(2n){background-color:var(--grid-zebra-even, var(--grid-surface))}.row-item:hover{background-color:var(--grid-row-hover)}.required-toggle-row{background-color:var(--grid-surface-container, #f3edf7);border-bottom:1px solid var(--grid-outline-variant, #cac4d0)}.required-toggle-row .required-toggle-cell{padding:4px 8px!important;text-align:center;vertical-align:middle;position:relative}.required-toggle-row .required-toggle-cell .required-label{position:absolute;top:2px;left:4px;font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:400;text-transform:lowercase}.required-toggle-row .required-toggle-cell mat-checkbox{display:flex;justify-content:center;align-items:center}.table-column-header{padding:var(--grid-header-padding-y) var(--grid-header-padding-x)}.column-header{font-weight:var(--grid-header-font-weight);text-transform:var(--grid-header-text-transform);letter-spacing:var(--grid-header-letter-spacing);text-align:center!important;font-size:var(--grid-header-font-size);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface))}.column-header:hover{background-color:var(--grid-header-hover-bg, var(--grid-surface-container-high))}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.sortable-header{cursor:pointer}.sortable-header .column-label{flex:1}.sortable-header .sort-indicator{display:inline-flex;align-items:center;gap:2px;margin-left:4px;cursor:pointer;vertical-align:middle;opacity:0;transition:opacity .15s ease}.sortable-header .sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.sortable-header .sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.sortable-header .sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-active{opacity:1}.sortable-header .sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-priority{font-size:9px;font-weight:600;color:var(--grid-primary, #6750a4);line-height:1;min-width:12px;text-align:center}.sortable-header:hover .sort-indicator,.sortable-header.sort-asc .sort-indicator,.sortable-header.sort-desc .sort-indicator{opacity:1}.sortable-header:hover .sort-indicator .sort-tri:not(.sort-tri-active){opacity:.6}.sort-asc,.sort-desc{background-color:var(--grid-surface-container-low, rgba(103, 80, 164, .04))}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:transparent;color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);font-feature-settings:var(--grid-font-feature-numeric);padding:var(--grid-cell-padding-y) var(--grid-cell-padding-x)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines:not(.freeze-header){border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-divider-width, 1px) * 2);background-color:var(--grid-divider-color, var(--grid-outline, #e0e0e0));pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th,.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}.incremental-row-container .eru-grid-table.show-row-lines thead th,.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}@media(max-width:768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media(prefers-contrast:high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media(prefers-reduced-motion:reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .pivot-repeated-value .cell-content,.pivot-table .pivot-repeated-value .pivot-cell-content{visibility:hidden}.pivot-table .pivot-group-start.row-dimension-cell{border-top:1px solid var(--grid-outline, #79757f)}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table{table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:calc(var(--grid-data-row-height, 50px) - 2px);display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:calc(var(--grid-data-row-height, 50px) - 4px);display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:var(--grid-header-row-height, 40px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}.group-header-row{display:flex;align-items:center;justify-content:space-between;width:100%;padding-right:12px}.custom-collapse-header{background-color:var(--grid-surface-variant);padding:8px 20px;border-top-left-radius:12px;border-top-right-radius:12px;cursor:pointer;display:flex;width:fit-content;align-items:center;-webkit-user-select:none;user-select:none;min-width:200px;margin-bottom:10px;position:sticky;left:1px;z-index:116}.custom-collapse-header .collapse-arrow{display:inline-block;margin-right:8px;font-size:12px;color:var(--grid-on-surface-variant);transition:transform .2s ease;transform:rotate(0)}.custom-collapse-header .collapse-arrow.rotate-arrow{transform:rotate(270deg)}.custom-collapse-header .f-12{font-size:12px;color:var(--grid-on-surface)}.custom-collapse-header .group-sort-indicator{display:inline-flex;align-items:center;margin-left:8px}.custom-collapse-header .group-sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.custom-collapse-header .group-sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.custom-collapse-header .group-sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-active{opacity:1}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.excel-download-icon{cursor:pointer}.excel-download-icon:hover{opacity:.75}.excel-download-bar{display:flex;justify-content:flex-end;padding:4px 12px}.table-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .header-shell::-webkit-scrollbar{display:none}.table-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-mode .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.table-mode .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.table-mode .subtotal-row td:first-child{color:var(--grid-primary)}.table-mode .subtotal-row td.subtotal-cell{font-weight:500}.table-mode .subtotal-row td.subtotal-cell .subtotal-label{font-weight:600;color:var(--grid-primary)}.table-mode .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.table-mode .subtotal-row.subtotal-bold td{font-weight:600!important;font-style:normal!important}.table-mode .subtotal-row.subtotal-italic td{font-style:italic!important}.table-mode .subtotal-row.subtotal-italic td:first-child{font-weight:600!important}.table-mode .subtotal-row.subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.table-mode .subtotal-row.subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.table-mode .subtotal-row.subtotal-highlighted:hover,.table-mode .subtotal-row.subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row-shell{width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .subtotal-row-shell::-webkit-scrollbar{display:none}.board-mode-host{overflow:hidden;display:flex;flex-direction:column;max-height:var(--grid-height, 600px)}.board-mode-host .board-view-container{display:flex;flex-direction:column;flex:1;min-height:0}.board-mode-host .board-sort-bar{display:flex;align-items:center;gap:6px;padding:8px 16px;flex-shrink:0;border-bottom:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);overflow-x:auto}.board-mode-host .board-sort-bar .board-sort-label{font-size:12px;font-weight:500;color:var(--grid-on-surface-variant, #49454f);white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);color:var(--grid-on-surface, #1d1b20);font-size:12px;white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip-active{background:var(--grid-surface-container);border-color:var(--grid-outline, #79757f);color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-sort-bar .board-sort-chip-label{pointer-events:none}.board-mode-host .board-sort-bar .board-sort-chip-arrow{font-size:10px;line-height:1;cursor:pointer;padding:2px;border-radius:4px}.board-mode-host .board-sort-bar .board-sort-chip-arrow:hover{background:#00000014}.board-mode-host .board-sort-bar .board-sort-chip-priority{font-size:9px;font-weight:700;background:var(--grid-primary, #6750a4);color:var(--grid-on-primary, #ffffff);border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center}.board-mode-host .board-sort-bar .board-sort-chip-remove{font-size:10px;cursor:pointer;padding:2px;border-radius:4px;color:var(--grid-on-surface-variant, #49454f)}.board-mode-host .board-sort-bar .board-sort-chip-remove:hover{background:#00000014;color:var(--grid-error, #b3261e)}.board-mode-host .board-sort-bar .board-sort-add-btn{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px dashed var(--grid-outline-variant, #cac4d0);background:transparent;color:var(--grid-on-surface-variant, #49454f);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease,border-color .15s ease}.board-mode-host .board-sort-bar .board-sort-add-btn .board-sort-add-icon{font-size:14px;width:14px;height:14px}.board-mode-host .board-sort-bar .board-sort-add-btn:hover{background:var(--grid-surface-container-low, #f7f2fa);border-color:var(--grid-primary, #6750a4);color:var(--grid-primary, #6750a4)}.board-mode-host .board-sort-bar .board-sort-clear{display:inline-flex;align-items:center;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-error, #b3261e);background:transparent;color:var(--grid-error, #b3261e);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease}.board-mode-host .board-sort-bar .board-sort-clear:hover{background:#b3261e14}.board-mode-host .board-columns-wrapper{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr)));grid-auto-rows:auto;align-items:start;gap:16px;flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;align-content:start;justify-content:start}.board-mode-host .board-columns-wrapper.board-columns-nowrap{grid-auto-flow:column;grid-template-columns:none;grid-template-rows:auto;grid-auto-rows:auto;grid-auto-columns:minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr));overflow-x:auto;overflow-y:hidden}.board-mode-host .board-column{max-height:var(--board-column-height, 420px);min-width:0;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column.board-column-accented{border-top:3px solid var(--board-group-color, transparent)}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 14px;font-weight:600;flex-shrink:0}.board-mode-host .board-column .column-header:hover{background-color:transparent}.board-mode-host .board-column .column-header .column-header-title{font-size:15px;font-weight:700;letter-spacing:.2px;line-height:1.2;color:var(--grid-on-surface, #1d1b20);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.board-mode-host .board-column .column-header .column-header-title-cell{display:inline-flex;align-items:center;flex:1 1 auto;min-width:0;overflow:visible;text-overflow:clip}.board-mode-host .board-column .column-header .column-header-title-cell data-cell,.board-mode-host .board-column .column-header .column-header-title-cell .data-cell-component,.board-mode-host .board-column .column-header .column-header-title-cell .container{padding:0!important;margin:0!important;border:none!important;background:transparent!important;min-height:0!important;height:auto!important;width:auto!important;max-width:100%!important;overflow:visible!important}.board-mode-host .board-column .column-header .column-header-title-cell .status-display,.board-mode-host .board-column .column-header .column-header-title-cell .status-display-content,.board-mode-host .board-column .column-header .column-header-title-cell .status-text,.board-mode-host .board-column .column-header .column-header-title-cell .tag-display,.board-mode-host .board-column .column-header .column-header-title-cell .tag-text{max-width:none!important;overflow:visible!important;text-overflow:clip!important}.board-mode-host .board-column .column-header .column-header-count{font-size:10px;font-weight:600;color:var(--eru-board-count-color, var(--grid-on-surface-variant, #49454f));background:var(--eru-board-count-bg, var(--grid-surface-variant, #e7e0ec));border-radius:10px;padding:3px 10px;white-space:nowrap;flex-shrink:0}.board-mode-host .board-column-body{flex:0 1 auto;min-height:0}.board-mode-host .board-card-container{box-sizing:border-box;overflow:hidden;border-radius:8px;transition:background-color .15s ease,box-shadow .15s ease}.board-mode-host .board-card-container.show-row-lines{box-shadow:inset 0 0 0 var(--grid-divider-width, 1px) var(--grid-divider-color, var(--grid-outline, #e0e0e0))}.board-mode-host .board-card-container:hover{background-color:var(--eru-board-card-hover-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 8%, transparent))}.board-mode-host .board-card-container.selected{background-color:var(--eru-board-card-selected-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 14%, transparent));box-shadow:inset 0 0 0 2px var(--eru-board-card-selected-outline, var(--mat-sys-primary, #1976d2))}.board-mode-host .board-card{height:calc(100% - 8px);overflow:hidden;cursor:pointer}.board-mode-host .board-card mat-card-title{font-size:13px}.board-mode-host .board-card mat-card-subtitle{font-size:12px}.board-mode-host .board-card-field{display:flex;flex-direction:column;margin-bottom:4px}.board-mode-host .board-field-label{font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:500;text-transform:uppercase;letter-spacing:.5px}.board-mode-host .board-ghost-card{margin:8px;padding:16px;background:var(--grid-surface, #fef7ff);border-radius:8px;animation:board-pulse 1.5s ease-in-out infinite}.board-mode-host .board-ghost-line{height:12px;background:var(--grid-surface-variant, #e7e0ec);border-radius:4px;margin-bottom:8px}.board-mode-host .board-ghost-line--short{width:60%}@keyframes board-pulse{0%,to{opacity:1}50%{opacity:.5}}th.row-expand-toggle,td.row-expand-toggle{width:40px!important;min-width:40px!important;max-width:40px!important;padding:0!important;text-align:center;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box}.row-expand-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);transition:transform .15s ease-in-out}.row-expand-icon.expanded{transform:rotate(90deg)}.row-detail{background:var(--grid-surface-container)}.row-detail .row-detail-cell{padding:var(--grid-spacing-sm) var(--grid-spacing-md);border-bottom:1px solid var(--grid-outline-variant)}.row-detail .row-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--grid-spacing-sm) var(--grid-spacing-md)}.row-detail .row-detail-field{display:flex;flex-direction:column;gap:var(--grid-spacing-xxs);min-width:0}.row-detail .row-detail-label{font-size:var(--grid-font-size-caption);color:var(--grid-on-surface-variant);font-weight:500}.row-detail .row-detail-value{min-width:0}.row-detail .row-detail-value data-cell{display:block;width:100%}\n"], dependencies: [{ kind: "component", type: DataCellComponent, selector: "data-cell", inputs: ["eruGridStore", "fieldSize", "columnDatatype", "columnName", "column", "value", "id", "frozenGrandTotalCell", "td", "drillable", "mode", "isEditable", "row", "personCardTemplate"], outputs: ["tdChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1$3.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1$3.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1$3.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i5.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i5.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: ResizeColumnDirective, selector: "[resizeColumn]", inputs: ["resizeColumn", "index", "columnConfig", "gridConfig"] }, { kind: "directive", type: ColumnDragDirective, selector: "[columnDraggable]", inputs: ["columnDraggable"] }, { kind: "component", type: ColumnDesignPanelComponent, selector: "eru-column-design-panel" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
14676
+ ], viewQueries: [{ propertyName: "rowContainer", first: true, predicate: ["rowContainer"], descendants: true }, { propertyName: "headerScroller", first: true, predicate: ["headerScroller"], descendants: true, read: ElementRef }, { propertyName: "gtScroller", first: true, predicate: ["gtScroller"], descendants: true, read: ElementRef }, { propertyName: "viewport", first: true, predicate: ["vp"], descendants: true }, { propertyName: "groupsViewport", first: true, predicate: ["groupsViewport"], descendants: true }, { propertyName: "groupsScrollContainerEl", first: true, predicate: ["groupsScrollContainer"], descendants: true }, { propertyName: "allViewports", predicate: CdkVirtualScrollViewport, descendants: true }, { propertyName: "headerScrollers", predicate: ["headerScroller"], descendants: true }], ngImport: i0, template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\ncurrentPivotScrollIndex {{currentPivotScrollIndex()}} |\nfirstDataRowIndex {{firstDataRowIndex()}} |\nfirstTr {{firstTr}} |\nmaxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode() && !isBoardMode()\" [class.board-mode-host]=\"isBoardMode()\">\n <eru-column-design-panel></eru-column-design-panel>\n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container>\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n\n\n <div class=\"pivot-single-table\"\n style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table>\n </div>\n }\n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport #vp [itemSize]=\"dataRowHeight()\" class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\" (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\" style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n\n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\" class=\"pivot-row\" [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) {\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.pivot-repeated-value]=\"isRepeatedDimensionValue(i, column.name)\"\n [class.pivot-group-start]=\"isPivotGroupStart(i, column.name)\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [personCardTemplate]=\"personCardTemplate\" [class.aggregation]=\"!!column.aggregationFunction\" [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\" [value]=\"pivotRow[column.name]\"\n [column]=\"column\" [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\"\n [isEditable]=\"isEditable()\" [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\"\n [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n } @else {\n <td [style.height.px]=\"dataRowHeight()\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\" [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n\n </table>\n </div>\n }\n\n\n </div>\n </div>\n </ng-container>\n } @else if (isBoardMode()) {\n <!-- Board Mode Template -->\n <div class=\"board-view-container\">\n @if(showSortBar()) {\n <div class=\"board-sort-bar\">\n <span class=\"board-sort-label\">Sort by:</span>\n @for (entry of gridStore.sortColumns(); track getFieldName(entry)) {\n <span class=\"board-sort-chip board-sort-chip-active\">\n <span class=\"board-sort-chip-label\">{{getColumnLabel(entry)}}</span>\n <span class=\"board-sort-chip-arrow\" (click)=\"onBoardSortChipToggle($event, entry)\">\n @if(!entry.startsWith('-')) { \u25B2 } @else { \u25BC }\n </span>\n @if(gridStore.sortColumns().length > 1) {\n <span class=\"board-sort-chip-priority\">{{getSortPriority(getFieldName(entry))}}</span>\n }\n <span class=\"board-sort-chip-remove\" (click)=\"onBoardSortChipRemove($event, entry)\">\u2715</span>\n </span>\n }\n <button class=\"board-sort-add-btn\" [matMenuTriggerFor]=\"sortFieldMenu\">\n <mat-icon class=\"board-sort-add-icon\">add</mat-icon> Add field\n </button>\n <mat-menu #sortFieldMenu=\"matMenu\" class=\"board-sort-menu\">\n @for (column of columns(); track column.name) {\n <button mat-menu-item (click)=\"onBoardSortFieldSelect(column)\"\n [disabled]=\"getSortDirection(column.name) !== null\">\n @if(getSortDirection(column.name) !== null) {\n <mat-icon>check</mat-icon>\n } @else {\n <mat-icon></mat-icon>\n }\n {{column.label}}\n </button>\n }\n </mat-menu>\n @if(gridStore.sortColumns().length > 0) {\n <button class=\"board-sort-clear\" (click)=\"onBoardSortClear()\">\u2715 Clear</button>\n }\n </div>\n }\n <div class=\"board-columns-wrapper\" [class.board-columns-nowrap]=\"!boardWrapColumns()\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\" [class.board-column-accented]=\"!!boardGroupColor(group)\"\n [style.--board-group-color]=\"boardGroupColor(group)\">\n @if (showBoardColumnHeader()) {\n <div class=\"column-header\">\n <!-- Render the group value through the same read-only cell renderer a\n data cell uses, so the grouped field's datatype formats itself\n (status/tag pills, dates, numbers) instead of printing raw text. -->\n @if (groupByColumn(); as gcol) {\n <span class=\"column-header-title column-header-title-cell\">\n <data-cell\n [eruGridStore]=\"gridStore\"\n [column]=\"gcol\"\n [columnDatatype]=\"gcol.datatype\"\n [columnName]=\"gcol.name\"\n [value]=\"group.title\"\n [id]=\"'board-group-' + group.id\"\n [fieldSize]=\"0\"\n [isEditable]=\"false\"\n [mode]=\"'board-group-header'\">\n </data-cell>\n </span>\n } @else {\n <span class=\"column-header-title\">{{ group.title }}</span>\n }\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n }\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"boardCardSlot\" class=\"board-column-body\"\n [style.height.px]=\"boardColumnBodyHeight(group)\"\n (scrolledIndexChange)=\"onBoardScrolledIndexChange($event, group)\">\n <div\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); templateCacheSize: 0\"\n class=\"board-card-container\"\n [class.selected]=\"isBoardCardActive(row)\"\n [class.show-row-lines]=\"showRowLines()\"\n [style.height.px]=\"boardCardOuterHeight\"\n [style.padding.px]=\"boardCardPadding\"\n [style.marginBottom.px]=\"boardCardGap\"\n [style.cursor]=\"cursorOnHover() || null\"\n (click)=\"emitRowSelect(row, 'board', group)\">\n <!-- Custom template when consumer provides boardCardTemplate; default card otherwise -->\n <ng-container\n *ngTemplateOutlet=\"boardCardTemplate ?? defaultBoardCard;\n context: { $implicit: row, columns: visibleBoardFields(), group: group }\">\n </ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n @if (group.isLoading) {\n <div class=\"board-ghost-card\">\n <div class=\"board-ghost-line\"></div>\n <div class=\"board-ghost-line board-ghost-line--short\"></div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n\n <!-- Table Mode Template -->\n <ng-template #excelDownloadIcon>\n <svg class=\"excel-download-icon\" title=\"Download Excel\" (click)=\"onExcelDownloadClick($event)\"\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"24px\" height=\"24px\">\n <path fill=\"#169154\" d=\"M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z\" />\n <path fill=\"#18482a\" d=\"M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z\" />\n <path fill=\"#0c8045\" d=\"M14 15.003H29V24.005000000000003H14z\" />\n <path fill=\"#17472a\" d=\"M14 24.005H29V33.055H14z\" />\n <g>\n <path fill=\"#29c27f\" d=\"M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z\" />\n <path fill=\"#27663f\" d=\"M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z\" />\n <path fill=\"#19ac65\" d=\"M29 15.003H44V24.005000000000003H29z\" />\n <path fill=\"#129652\" d=\"M29 24.005H44V33.055H29z\" />\n </g>\n <path fill=\"#0c7238\"\n d=\"M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z\" />\n <path fill=\"#fff\"\n d=\"M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z\" />\n </svg>\n </ng-template>\n @if(showExcelDownload() && !showGroupBar()) {\n <div class=\"excel-download-bar\">\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n </div>\n }\n <!-- Scrollable groups container \u2014 plain iteration avoids CDK fixed-height estimation errors -->\n <div #groupsScrollContainer class=\"groups-scroll-container\" (scroll)=\"onGroupsViewportScroll($event)\">\n\n @for (group of groups(); track trackByGroupFn($index, group); let i = $index) {\n <div class=\"group-container\"\n [attr.data-group-id]=\"group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id\">\n <!-- Combined sticky header with group info and table -->\n <div style=\"\n background:var(--grid-surface);\n position: sticky;\n top: 0;\n z-index: 115;\n \">\n @if(showGroupBar()) {\n <div class=\"group-header-row\">\n <div class=\"custom-collapse-header\" (click)=\"toggleGroupCollapse(group.id)\">\n <span class=\"collapse-arrow\" [ngClass]=\"{\n 'rotate-arrow': group.isExpanded,\n }\">\u25BC</span>\n <span class=\"f-12\">\n {{ group?.title || \"\" }}\n {{ group?.currentLoadedRows || 0 }} -\n {{ group?.totalRowCount || 0 }} rows...</span>\n @if(groupByField() && isSortable()) {\n <span class=\"group-sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'asc'\"\n (click)=\"onGroupSortToggle($event, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\"\n [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'desc'\"\n (click)=\"onGroupSortToggle($event, 'desc')\"></span>\n </span>\n </span>\n }\n </div>\n @if(i === 0 && showExcelDownload()) {\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n }\n </div>\n }\n\n @if(freezeHeader() && (group.isExpanded || !showGroupBar())) {\n <div #headerScroller class=\"header-shell\" [attr.data-group-id]=\"'header-shell-' + group.id\"\n [style]=\"'--table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <table class=\"eru-grid-table\" [class.freeze-header]=\"freezeHeader()\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n <!-- Grand Total row after sticky header (position: before) - only for first group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' && hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after sticky header (position: before) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'before' && hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n </table>\n </div>\n }\n </div>\n @if(group.isExpanded || !showGroupBar()) {\n <ng-container>\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"dataRowHeight()\" class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event, group)\" (scroll)=\"onTableBodyScroll($event)\"\n [style]=\"'--table-height: ' + getGroupContentHeight(group.id) + 'px; --table-min-height: ' + getGroupContentHeight(group.id) + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <div class=\"table-wrapper\">\n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\"\n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n @if(!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n }\n <!-- Grand Total row after normal header (position: before) - only for first group -->\n @if(!freezeHeader() && enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' &&\n hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after normal header (position: before) -->\n @if(!freezeHeader() && enableColumnSubtotals() && subtotalPositionColumn() === 'before' &&\n hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n <tbody>\n @if (columns(); as columnsList) {\n <!-- <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr> -->\n <!-- @if(getRowsForGroup(group.id).length > 0 && group.isExpanded) { -->\n <!-- *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id)(); \n trackBy: trackByRowFn; \n let i = index\" -->\n <!-- @for(row of getRowsForGroupSignal(group.id)(); track trackByRowFn($index, row); let i = $index) { -->\n <ng-container\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); trackBy: trackByRowFn; let i = index\">\n <tr class=\"row-item\" [attr.data-row-id]=\"i\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" (click)=\"emitRowSelect(row, 'table', group)\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input type=\"checkbox\" [checked]=\"isRowSelected(row?.entity_id)\"\n (change)=\"toggleRowSelection($event, row)\">\n </td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\" (click)=\"toggleRowExpand(row, i, $event)\">\n <mat-icon class=\"row-expand-icon\" [class.expanded]=\"isRowExpanded(row, i)\">chevron_right</mat-icon>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td #cell [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\"\n [matTooltipClass]=\"'error-message'\" [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\">\n <div class=\"cell-content\">\n <data-cell #datacell [personCardTemplate]=\"personCardTemplate\" [td]=cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\" [value]=\"(row?.['entity_data']?.[column.name] ?? row?.[column.name]) || ''\" [column]=\"column\"\n [mode]=\"mode()\" [isEditable]=\"isEditable() && column.editable !== false && column.editable !== 'false'\" [drillable]=\"column.enableDrilldown || false\"\n [id]=\"i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n </tr>\n @if(hasHiddenColumns() && isRowExpanded(row, i)) {\n <tr class=\"row-detail\">\n <td class=\"row-detail-cell\" [attr.colspan]=\"rowDetailColspan()\">\n <div class=\"row-detail-grid\">\n @for (hiddenCol of hiddenColumns(); track trackByColumnFn($index, hiddenCol)) {\n <div class=\"row-detail-field\">\n <span class=\"row-detail-label\">{{hiddenCol.label}}</span>\n <div class=\"row-detail-value\">\n <data-cell [fieldSize]=\"hiddenCol.field_size\" [columnDatatype]=\"hiddenCol.datatype\"\n [columnName]=\"hiddenCol.name\" [value]=\"(row?.['entity_data']?.[hiddenCol.name] ?? row?.[hiddenCol.name]) || ''\"\n [column]=\"hiddenCol\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [drillable]=\"hiddenCol.enableDrilldown || false\"\n [id]=\"'detail_' + i + '_' + hiddenCol.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-container>\n <!-- } -->\n <!-- } -->\n @if(group.isLoading && (group.isExpanded || !showGroupBar())) {\n @for(i of [].constructor(ghostRows()); let j = $index; track j) {\n <tr class=\"ghost-loading-row\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n </tr>\n }\n }\n <!-- <tr\n *ngIf=\"getRowsForGroup(group.id).length === 0 && !group.isExpanded\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr> -->\n <!-- Subtotal row at end of group (position: after) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'after' && hasSubtotalData(group)) {\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n }\n <!-- Grand Total row at end of group (position: after) - only for last group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'after' && hasGrandTotalData() && i ===\n groups().length - 1) {\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n }\n }\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container>\n }\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Pivot Table Header Template -->\n<ng-template #pivotTableHead>\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n @if (hasNestedHeaders()) {\n <ng-container>\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th [attr.colspan]=\"header.colspan\" [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"isResizablePivotHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header) || $any(header)\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\" [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\" [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor($any(header))\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n\n <data-cell [fieldSize]=\"header.field_size\" [columnDatatype]=\"header.dataType\" [columnName]=\"header.name\"\n [value]=\"header.label\" [column]=\"header\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\" [eruGridStore]=\"gridStore\" [row]=\"header\">\n </data-cell>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader($any(header)) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, $any(header))\">tune</mat-icon>\n }\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\"\n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\" [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\" [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor(column)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto;padding: 8px 6px\">\n <!-- Label and control laid out as a row: the label truncates, the\n control keeps its place. Left as a bare text node the long\n aggregation labels pushed the icon past the cell edge, where\n `overflow: hidden` clipped it out of sight entirely. -->\n <div class=\"pivot-header-content\">\n <!-- Deliberately not `.column-label`: that class carries the\n wrap-headers rule, which broke these labels onto one word per\n line. This header truncates, as it did before. -->\n <span class=\"pivot-header-label\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader(column) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n </div>\n </th>\n }\n </tr>\n </ng-container>\n }\n\n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n <tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\" [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"50\" [attr.xx]=\"i\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\" [column]=\"column\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n }\n </tbody>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Action column cell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One template for both column positions. With no `config.actions` set it\n falls back to the single more_horiz icon the column has always shown, so\n grids that only listen to the store's actionClick signal keep working.\n Context: { $implicit: Row, mode: 'table' | 'board', group?: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #actionCell let-row let-mode=\"mode\" let-group=\"group\">\n @if(!hasConfiguredActions()) {\n <mat-icon (click)=\"onActionClick($event, row, undefined, mode || 'table', group)\">more_horiz</mat-icon>\n } @else if(actionDisplayType() === 'kebab') {\n @if(visibleActionsFor(row).length > 0) {\n <mat-icon class=\"action-kebab\" [matMenuTriggerFor]=\"rowActionMenu\"\n [matMenuTriggerData]=\"{ row: row, mode: mode || 'table', group: group }\"\n (click)=\"$event.stopPropagation()\">more_vert</mat-icon>\n }\n } @else {\n <div class=\"action-icons\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <mat-icon class=\"action-icon\" [matTooltip]=\"action.action_name\" matTooltipPosition=\"above\"\n (click)=\"onActionClick($event, row, action, mode || 'table', group)\">{{action.action_icon || 'play_arrow'}}</mat-icon>\n }\n </div>\n }\n</ng-template>\n\n<!-- Kebab menu shared by every row; the row is passed through matMenuTriggerData. -->\n<mat-menu #rowActionMenu=\"matMenu\" class=\"eru-grid-action-menu\">\n <ng-template matMenuContent let-row=\"row\" let-mode=\"mode\" let-group=\"group\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <button mat-menu-item (click)=\"onActionClick($event, row, action, mode || 'table', group)\">\n <mat-icon>{{action.action_icon || 'play_arrow'}}</mat-icon>\n <span>{{action.action_name}}</span>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #tableColGroup>\n <colgroup>\n @if(gridStore.configuration().config.allowSelection) {\n <col style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n }\n @if(shouldShowActionColumn('before')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n @if(hasHiddenColumns()) {\n <col style=\"width: 40px !important; min-width: 40px !important; max-width: 40px !important;\">\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n @if(shouldShowActionColumn('after')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n </colgroup>\n</ng-template>\n\n\n<ng-template #tableHeader>\n\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n <!-- headerRowHeight rides on the row, not the cells: `thead.eru-wrap-headers\n th { height: auto }` outranks any class-level height we could put on a\n th, which is why a configured header height was ignored while data rows\n (inline height on tr.row-item) honoured theirs. On a table row `height`\n is a minimum, so a wrapped two-line header still grows past it. -->\n <tr [style.height.px]=\"headerRowHeight()\" [style.minHeight.px]=\"headerRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column column-header table-column-header\">\n <input type=\"checkbox\" [checked]=\"isAllGroupsSelected()\" (change)=\"toggleAllGroups($event)\">\n </th>\n }\n @if(shouldShowActionColumn('before')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n @if(hasHiddenColumns()) {\n <th class=\"row-expand-toggle column-header table-column-header\"></th>\n }\n @for (column of visibleColumns(); track trackByColumnFn(i, column); let i = $index) {\n <th [style.width.px]=\"column.field_size\" [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\" [index]=\"i\"\n [columnDraggable]=\"gridStore.isFeatureEnabled('columnReorderable') ? i : null\"\n [style.minWidth.px]=\"column.field_size\" class=\"column-header table-column-header\"\n [class.sortable-header]=\"isSortable()\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === column.name\"\n [class.sort-asc]=\"isSortable() && getSortDirection(column.name) === 'asc'\"\n [class.sort-desc]=\"isSortable() && getSortDirection(column.name) === 'desc'\">\n @if(gridStore.isFeatureEnabled('columnReorderable')) {\n <div class=\"column-drag-handle\"></div>\n }\n <span class=\"column-label\" [title]=\"column.tool_tip || column.description || ''\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\" title=\"Edit column\" (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n @if(isSortable()) {\n <span class=\"sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'asc'\"\n (click)=\"onSortColumn($event, column, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'desc'\"\n (click)=\"onSortColumn($event, column, 'desc')\"></span>\n </span>\n @if(getSortPriority(column.name) !== null && gridStore.sortColumns().length > 1) {\n <span class=\"sort-priority\">{{getSortPriority(column.name)}}</span>\n }\n </span>\n }\n </th>\n }\n @if(shouldShowActionColumn('after')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n </tr>\n </thead>\n</ng-template>\n\n<!-- Table Subtotal Row Template -->\n<ng-template #tableSubtotal let-group=\"group\">\n <tr class=\"subtotal-row\" [class.subtotal-bold]=\"subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"subTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"subtotal-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getSubtotalValue(group, column.name) === null) {\n <span class=\"subtotal-label\">{{subtotalLabel()}}</span>\n } @else {\n @if(getSubtotalValue(group, column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getSubtotalValue(group, column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'subtotal_' + group.id + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"group.subtotal\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- Table Grand Total Row Template -->\n<ng-template #tableGrandTotal>\n <tr class=\"grand-total-row\" [class.grand-total-bold]=\"grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"grandTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"grand-total-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getGrandTotalValue(column.name) === null) {\n <span class=\"grand-total-label\">Grand Total</span>\n } @else {\n @if(getGrandTotalValue(column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getGrandTotalValue(column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'grandtotal_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"gridStore.rowGrandTotal()\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Default board card template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Used when no boardCardTemplate is passed to <eru-grid>.\n Context: { $implicit: Row, columns: Field[], group: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #defaultBoardCard let-row let-columns=\"columns\" let-group=\"group\">\n <mat-card class=\"board-card\">\n <mat-card-content>\n @for (column of columns; track column.name) {\n @if ((row?.entity_data?.[column.name] ?? row?.[column.name]) !== undefined) {\n <div class=\"board-card-field\">\n <span class=\"board-field-label\">{{ column.label }}</span>\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [column]=\"column\"\n [value]=\"row?.entity_data?.[column.name] ?? row?.[column.name]\"\n [id]=\"row?.entity_id + '_' + column.name\"\n [eruGridStore]=\"gridStore\"\n [mode]=\"'board'\"\n [row]=\"row\">\n </data-cell>\n </div>\n }\n }\n </mat-card-content>\n <mat-card-actions align=\"end\">\n <button mat-icon-button (click)=\"onActionClick($event, row)\">\n <mat-icon>more_horiz</mat-icon>\n </button>\n </mat-card-actions>\n </mat-card>\n</ng-template>", styles: ["@charset \"UTF-8\";:root{--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6}:host,eru-grid{display:block!important;width:100%;height:100%;flex:1 1 0%;max-height:var(--grid-height, none);min-height:var(--grid-min-height, 120px);font-family:var(--grid-font-family);--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15);--grid-row-hover: var(--grid-surface-variant);--grid-row-selected: var(--grid-surface-container-high);--grid-zebra-odd: transparent;--grid-zebra-even: transparent;--grid-focus-ring: var(--grid-primary);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: var(--grid-font-size-caption);--grid-header-padding-x: 8px;--grid-header-padding-y: 12px;--grid-font-feature-numeric: normal;--grid-cell-padding-x: var(--grid-spacing-xs);--grid-cell-padding-y: var(--grid-spacing-xxs);--grid-tint-subtle: rgba(0, 0, 0, .025);--grid-tint-soft: rgba(0, 0, 0, .045);--grid-tint-strong: rgba(0, 0, 0, .08);--grid-radius-outer: 0;--grid-shadow-outer: none;--grid-divider-color: var(--grid-outline-variant);--grid-divider-width: 1px;--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-pill-radius: 999px;--grid-pill-padding-y: 3px;--grid-pill-padding-x: 10px;--grid-pill-font-size: 11px;--grid-pill-font-weight: 500;--grid-priority-dot-size: 8px;--grid-avatar-size: 24px;--grid-avatar-font-size: 10px;--grid-avatar-font-weight: 600;border-radius:var(--grid-radius-outer);box-shadow:var(--grid-shadow-outer)}eru-grid[data-preset=default]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .06em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-soft);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=modern]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: 13px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 16px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 12px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px}eru-grid[data-preset=compact]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 11px;--grid-header-padding-y: 4px;--grid-header-padding-x: 8px;--grid-cell-padding-y: 3px;--grid-cell-padding-x: 8px;--grid-font-size-body: 11px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 1px;--grid-pill-padding-x: 6px;--grid-pill-font-size: 10px}eru-grid[data-preset=bold]{--grid-header-bg: var(--grid-surface-container-high);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 700;--grid-header-text-transform: none;--grid-header-font-size: 13px;--grid-header-padding-y: 14px;--grid-header-padding-x: 12px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 12px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-strong);--grid-divider-width: 1px;--grid-radius-outer: 2px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=financial]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .08em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-zebra-odd: transparent;--grid-zebra-even: var(--grid-tint-subtle);--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=elevated]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 12px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 14px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 16px;--grid-shadow-outer: 0 1px 3px rgba(0, 0, 0, .06), 0 10px 28px rgba(0, 0, 0, .07);--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px;overflow:hidden}.group-container{padding-bottom:8px}.column-header.design-clickable .design-edit-icon{font-size:16px;width:16px;height:16px;margin-left:4px;opacity:.45;vertical-align:middle;cursor:pointer}.column-header.design-clickable:hover .design-edit-icon,.column-header.design-clickable .design-edit-icon:hover{opacity:1}.column-header.design-selected{background-color:var(--grid-primary-light, rgba(63, 81, 181, .12))}.pivot-column-header .pivot-header-content{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}.pivot-column-header .pivot-header-content .pivot-header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.pivot-column-header .pivot-header-content .design-edit-icon,.pivot-column-header .header-content .design-edit-icon{flex:0 0 auto}.pivot-column-header .header-content data-cell,.pivot-column-header .header-content data-cell *{color:inherit!important}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-min-height, 120px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);font-family:var(--grid-font-family)}.viewport{height:100%;min-height:300px;overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.groups-viewport{height:100%;min-height:300px}.groups-scroll-container{max-height:var(--grid-height, 600px);overflow-y:auto;overflow-x:hidden}.table-viewport{background-color:var(--grid-surface);height:var(--table-height, auto);min-height:var(--table-min-height, 100px);overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th{background-color:var(--grid-header-bg, var(--grid-surface-container))}thead.eru-wrap-headers th{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;height:auto}thead.eru-wrap-headers th .column-label,thead.eru-wrap-headers th .header-label{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;word-break:break-word;overflow-wrap:anywhere}.eru-grid-table tbody td{background-color:transparent}.eru-grid-table thead{background-color:var(--grid-header-bg, var(--grid-surface-container));transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{position:sticky!important;top:0!important;z-index:100!important}.eru-grid-table thead th{background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface));font-family:var(--grid-font-family);font-weight:var(--grid-header-font-weight);font-size:var(--grid-header-font-size)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.action-column{text-align:center;background-color:var(--grid-surface-container)}.action-column mat-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);cursor:pointer}.action-column mat-icon:hover{color:var(--grid-primary)}.action-column .action-icons{display:flex;align-items:center;justify-content:center;gap:6px;overflow-x:auto;scrollbar-width:none}.action-column .action-icons::-webkit-scrollbar{display:none}.action-column .action-icon{flex:0 0 auto}.eru-grid-action-menu .mat-mdc-menu-item mat-icon{margin-right:8px;font-size:18px;width:18px;height:18px;line-height:18px;color:var(--grid-on-surface-variant)}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{background-color:var(--grid-surface);transition:background-color .15s ease}.row-item:nth-child(odd){background-color:var(--grid-zebra-odd, var(--grid-surface))}.row-item:nth-child(2n){background-color:var(--grid-zebra-even, var(--grid-surface))}.row-item:hover{background-color:var(--grid-row-hover)}.required-toggle-row{background-color:var(--grid-surface-container, #f3edf7);border-bottom:1px solid var(--grid-outline-variant, #cac4d0)}.required-toggle-row .required-toggle-cell{padding:4px 8px!important;text-align:center;vertical-align:middle;position:relative}.required-toggle-row .required-toggle-cell .required-label{position:absolute;top:2px;left:4px;font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:400;text-transform:lowercase}.required-toggle-row .required-toggle-cell mat-checkbox{display:flex;justify-content:center;align-items:center}.table-column-header{padding:0 var(--grid-header-padding-x);height:var(--grid-header-row-height, auto)}.column-header{font-weight:var(--grid-header-font-weight);text-transform:var(--grid-header-text-transform);letter-spacing:var(--grid-header-letter-spacing);text-align:center!important;font-size:var(--grid-header-font-size);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface))}.column-header:hover{background-color:var(--grid-header-hover-bg, var(--grid-surface-container-high))}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.sortable-header{cursor:pointer}.sortable-header .column-label{flex:1}.sortable-header .sort-indicator{display:inline-flex;align-items:center;gap:2px;margin-left:4px;cursor:pointer;vertical-align:middle;opacity:0;transition:opacity .15s ease}.sortable-header .sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.sortable-header .sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.sortable-header .sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-active{opacity:1}.sortable-header .sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-priority{font-size:9px;font-weight:600;color:var(--grid-primary, #6750a4);line-height:1;min-width:12px;text-align:center}.sortable-header:hover .sort-indicator,.sortable-header.sort-asc .sort-indicator,.sortable-header.sort-desc .sort-indicator{opacity:1}.sortable-header:hover .sort-indicator .sort-tri:not(.sort-tri-active){opacity:.6}.sort-asc,.sort-desc{background-color:var(--grid-surface-container-low, rgba(103, 80, 164, .04))}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:transparent;color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);font-feature-settings:var(--grid-font-feature-numeric);padding:0 var(--grid-cell-padding-x)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines:not(.freeze-header){border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-divider-width, 1px) * 2);background-color:var(--grid-divider-color, var(--grid-outline, #e0e0e0));pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th,.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}.incremental-row-container .eru-grid-table.show-row-lines thead th,.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}@media(max-width:768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media(prefers-contrast:high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media(prefers-reduced-motion:reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .pivot-repeated-value .cell-content,.pivot-table .pivot-repeated-value .pivot-cell-content{visibility:hidden}.pivot-table .pivot-group-start.row-dimension-cell{border-top:1px solid var(--grid-outline, #79757f)}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table{table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:calc(var(--grid-data-row-height, 50px) - 2px);display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:calc(var(--grid-data-row-height, 50px) - 4px);display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:var(--grid-header-row-height, 40px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}.group-header-row{display:flex;align-items:center;justify-content:space-between;width:100%;padding-right:12px}.custom-collapse-header{background-color:var(--grid-surface-variant);padding:8px 20px;border-top-left-radius:12px;border-top-right-radius:12px;cursor:pointer;display:flex;width:fit-content;align-items:center;-webkit-user-select:none;user-select:none;min-width:200px;margin-bottom:10px;position:sticky;left:1px;z-index:116}.custom-collapse-header .collapse-arrow{display:inline-block;margin-right:8px;font-size:12px;color:var(--grid-on-surface-variant);transition:transform .2s ease;transform:rotate(0)}.custom-collapse-header .collapse-arrow.rotate-arrow{transform:rotate(270deg)}.custom-collapse-header .f-12{font-size:12px;color:var(--grid-on-surface)}.custom-collapse-header .group-sort-indicator{display:inline-flex;align-items:center;margin-left:8px}.custom-collapse-header .group-sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.custom-collapse-header .group-sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.custom-collapse-header .group-sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-active{opacity:1}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.excel-download-icon{cursor:pointer}.excel-download-icon:hover{opacity:.75}.excel-download-bar{display:flex;justify-content:flex-end;padding:4px 12px}.table-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .header-shell::-webkit-scrollbar{display:none}.table-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-mode .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.table-mode .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.table-mode .subtotal-row td:first-child{color:var(--grid-primary)}.table-mode .subtotal-row td.subtotal-cell{font-weight:500}.table-mode .subtotal-row td.subtotal-cell .subtotal-label{font-weight:600;color:var(--grid-primary)}.table-mode .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.table-mode .subtotal-row.subtotal-bold td{font-weight:600!important;font-style:normal!important}.table-mode .subtotal-row.subtotal-italic td{font-style:italic!important}.table-mode .subtotal-row.subtotal-italic td:first-child{font-weight:600!important}.table-mode .subtotal-row.subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.table-mode .subtotal-row.subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.table-mode .subtotal-row.subtotal-highlighted:hover,.table-mode .subtotal-row.subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row-shell{width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .subtotal-row-shell::-webkit-scrollbar{display:none}.board-mode-host{overflow:hidden;display:flex;flex-direction:column;max-height:var(--grid-height, 600px)}.board-mode-host .board-view-container{display:flex;flex-direction:column;flex:1;min-height:0}.board-mode-host .board-sort-bar{display:flex;align-items:center;gap:6px;padding:8px 16px;flex-shrink:0;border-bottom:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);overflow-x:auto}.board-mode-host .board-sort-bar .board-sort-label{font-size:12px;font-weight:500;color:var(--grid-on-surface-variant, #49454f);white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);color:var(--grid-on-surface, #1d1b20);font-size:12px;white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip-active{background:var(--grid-surface-container);border-color:var(--grid-outline, #79757f);color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-sort-bar .board-sort-chip-label{pointer-events:none}.board-mode-host .board-sort-bar .board-sort-chip-arrow{font-size:10px;line-height:1;cursor:pointer;padding:2px;border-radius:4px}.board-mode-host .board-sort-bar .board-sort-chip-arrow:hover{background:#00000014}.board-mode-host .board-sort-bar .board-sort-chip-priority{font-size:9px;font-weight:700;background:var(--grid-primary, #6750a4);color:var(--grid-on-primary, #ffffff);border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center}.board-mode-host .board-sort-bar .board-sort-chip-remove{font-size:10px;cursor:pointer;padding:2px;border-radius:4px;color:var(--grid-on-surface-variant, #49454f)}.board-mode-host .board-sort-bar .board-sort-chip-remove:hover{background:#00000014;color:var(--grid-error, #b3261e)}.board-mode-host .board-sort-bar .board-sort-add-btn{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px dashed var(--grid-outline-variant, #cac4d0);background:transparent;color:var(--grid-on-surface-variant, #49454f);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease,border-color .15s ease}.board-mode-host .board-sort-bar .board-sort-add-btn .board-sort-add-icon{font-size:14px;width:14px;height:14px}.board-mode-host .board-sort-bar .board-sort-add-btn:hover{background:var(--grid-surface-container-low, #f7f2fa);border-color:var(--grid-primary, #6750a4);color:var(--grid-primary, #6750a4)}.board-mode-host .board-sort-bar .board-sort-clear{display:inline-flex;align-items:center;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-error, #b3261e);background:transparent;color:var(--grid-error, #b3261e);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease}.board-mode-host .board-sort-bar .board-sort-clear:hover{background:#b3261e14}.board-mode-host .board-columns-wrapper{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr)));grid-auto-rows:auto;align-items:start;gap:16px;flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;align-content:start;justify-content:start}.board-mode-host .board-columns-wrapper.board-columns-nowrap{grid-auto-flow:column;grid-template-columns:none;grid-template-rows:auto;grid-auto-rows:auto;grid-auto-columns:minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr));overflow-x:auto;overflow-y:hidden}.board-mode-host .board-column{max-height:var(--board-column-height, 420px);min-width:0;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column.board-column-accented{border-top:3px solid var(--board-group-color, transparent)}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 14px;font-weight:600;flex-shrink:0;background-color:transparent}.board-mode-host .board-column .column-header:hover{background-color:transparent}.board-mode-host .board-column .column-header .column-header-title{font-size:15px;font-weight:700;letter-spacing:.2px;line-height:1.2;color:var(--grid-on-surface, #1d1b20);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.board-mode-host .board-column .column-header .column-header-title-cell{display:inline-flex;align-items:center;flex:1 1 auto;min-width:0;overflow:visible;text-overflow:clip}.board-mode-host .board-column .column-header .column-header-title-cell data-cell,.board-mode-host .board-column .column-header .column-header-title-cell .data-cell-component,.board-mode-host .board-column .column-header .column-header-title-cell .container{padding:0!important;margin:0!important;border:none!important;background:transparent!important;min-height:0!important;height:auto!important;width:auto!important;max-width:100%!important;overflow:visible!important}.board-mode-host .board-column .column-header .column-header-title-cell .status-display,.board-mode-host .board-column .column-header .column-header-title-cell .status-display-content,.board-mode-host .board-column .column-header .column-header-title-cell .status-text,.board-mode-host .board-column .column-header .column-header-title-cell .tag-display,.board-mode-host .board-column .column-header .column-header-title-cell .tag-text{max-width:none!important;overflow:visible!important;text-overflow:clip!important}.board-mode-host .board-column .column-header .column-header-count{font-size:10px;font-weight:600;color:var(--eru-board-count-color, var(--grid-on-surface-variant, #49454f));background:var(--eru-board-count-bg, var(--grid-surface-variant, #e7e0ec));border-radius:10px;padding:3px 10px;white-space:nowrap;flex-shrink:0}.board-mode-host .board-column-body{flex:0 1 auto;min-height:0}.board-mode-host .board-card-container{box-sizing:border-box;overflow:hidden;border-radius:8px;transition:background-color .15s ease,box-shadow .15s ease}.board-mode-host .board-card-container.show-row-lines{box-shadow:inset 0 0 0 var(--grid-divider-width, 1px) var(--grid-divider-color, var(--grid-outline, #e0e0e0))}.board-mode-host .board-card-container:hover{background-color:var(--eru-board-card-hover-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 8%, transparent))}.board-mode-host .board-card-container.selected{background-color:var(--eru-board-card-selected-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 14%, transparent));box-shadow:inset 0 0 0 2px var(--eru-board-card-selected-outline, var(--mat-sys-primary, #1976d2))}.board-mode-host .board-card{height:calc(100% - 8px);overflow:hidden;cursor:pointer}.board-mode-host .board-card mat-card-title{font-size:13px}.board-mode-host .board-card mat-card-subtitle{font-size:12px}.board-mode-host .board-card-field{display:flex;flex-direction:column;margin-bottom:4px}.board-mode-host .board-field-label{font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:500;text-transform:uppercase;letter-spacing:.5px}.board-mode-host .board-ghost-card{margin:8px;padding:16px;background:var(--grid-surface, #fef7ff);border-radius:8px;animation:board-pulse 1.5s ease-in-out infinite}.board-mode-host .board-ghost-line{height:12px;background:var(--grid-surface-variant, #e7e0ec);border-radius:4px;margin-bottom:8px}.board-mode-host .board-ghost-line--short{width:60%}@keyframes board-pulse{0%,to{opacity:1}50%{opacity:.5}}th.row-expand-toggle,td.row-expand-toggle{width:40px!important;min-width:40px!important;max-width:40px!important;padding:0!important;text-align:center;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box}.row-expand-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);transition:transform .15s ease-in-out}.row-expand-icon.expanded{transform:rotate(90deg)}.row-detail{background:var(--grid-surface-container)}.row-detail .row-detail-cell{padding:var(--grid-spacing-sm) var(--grid-spacing-md);border-bottom:1px solid var(--grid-outline-variant)}.row-detail .row-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--grid-spacing-sm) var(--grid-spacing-md)}.row-detail .row-detail-field{display:flex;flex-direction:column;gap:var(--grid-spacing-xxs);min-width:0}.row-detail .row-detail-label{font-size:var(--grid-font-size-caption);color:var(--grid-on-surface-variant);font-weight:500}.row-detail .row-detail-value{min-width:0}.row-detail .row-detail-value data-cell{display:block;width:100%}\n"], dependencies: [{ kind: "component", type: DataCellComponent, selector: "data-cell", inputs: ["eruGridStore", "fieldSize", "columnDatatype", "columnName", "column", "value", "id", "frozenGrandTotalCell", "td", "drillable", "mode", "isEditable", "row", "personCardTemplate"], outputs: ["tdChange"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i1$3.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i1$3.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i1$3.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i5.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i5.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: ResizeColumnDirective, selector: "[resizeColumn]", inputs: ["resizeColumn", "index", "columnConfig", "gridConfig"] }, { kind: "directive", type: ColumnDragDirective, selector: "[columnDraggable]", inputs: ["columnDraggable"] }, { kind: "component", type: ColumnDesignPanelComponent, selector: "eru-column-design-panel" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
14625
14677
  }
14626
14678
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EruGridComponent, decorators: [{
14627
14679
  type: Component,
@@ -14641,7 +14693,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
14641
14693
  ResizeColumnDirective,
14642
14694
  ColumnDragDirective,
14643
14695
  ColumnDesignPanelComponent
14644
- ], template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\ncurrentPivotScrollIndex {{currentPivotScrollIndex()}} |\nfirstDataRowIndex {{firstDataRowIndex()}} |\nfirstTr {{firstTr}} |\nmaxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode() && !isBoardMode()\" [class.board-mode-host]=\"isBoardMode()\">\n <eru-column-design-panel></eru-column-design-panel>\n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container>\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n\n\n <div class=\"pivot-single-table\"\n style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table>\n </div>\n }\n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport #vp [itemSize]=\"dataRowHeight()\" class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\" (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\" style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n\n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\" class=\"pivot-row\" [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) {\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.pivot-repeated-value]=\"isRepeatedDimensionValue(i, column.name)\"\n [class.pivot-group-start]=\"isPivotGroupStart(i, column.name)\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [personCardTemplate]=\"personCardTemplate\" [class.aggregation]=\"!!column.aggregationFunction\" [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\" [value]=\"pivotRow[column.name]\"\n [column]=\"column\" [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\"\n [isEditable]=\"isEditable()\" [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\"\n [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n } @else {\n <td [style.height.px]=\"dataRowHeight()\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\" [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n\n </table>\n </div>\n }\n\n\n </div>\n </div>\n </ng-container>\n } @else if (isBoardMode()) {\n <!-- Board Mode Template -->\n <div class=\"board-view-container\">\n @if(showSortBar()) {\n <div class=\"board-sort-bar\">\n <span class=\"board-sort-label\">Sort by:</span>\n @for (entry of gridStore.sortColumns(); track getFieldName(entry)) {\n <span class=\"board-sort-chip board-sort-chip-active\">\n <span class=\"board-sort-chip-label\">{{getColumnLabel(entry)}}</span>\n <span class=\"board-sort-chip-arrow\" (click)=\"onBoardSortChipToggle($event, entry)\">\n @if(!entry.startsWith('-')) { \u25B2 } @else { \u25BC }\n </span>\n @if(gridStore.sortColumns().length > 1) {\n <span class=\"board-sort-chip-priority\">{{getSortPriority(getFieldName(entry))}}</span>\n }\n <span class=\"board-sort-chip-remove\" (click)=\"onBoardSortChipRemove($event, entry)\">\u2715</span>\n </span>\n }\n <button class=\"board-sort-add-btn\" [matMenuTriggerFor]=\"sortFieldMenu\">\n <mat-icon class=\"board-sort-add-icon\">add</mat-icon> Add field\n </button>\n <mat-menu #sortFieldMenu=\"matMenu\" class=\"board-sort-menu\">\n @for (column of columns(); track column.name) {\n <button mat-menu-item (click)=\"onBoardSortFieldSelect(column)\"\n [disabled]=\"getSortDirection(column.name) !== null\">\n @if(getSortDirection(column.name) !== null) {\n <mat-icon>check</mat-icon>\n } @else {\n <mat-icon></mat-icon>\n }\n {{column.label}}\n </button>\n }\n </mat-menu>\n @if(gridStore.sortColumns().length > 0) {\n <button class=\"board-sort-clear\" (click)=\"onBoardSortClear()\">\u2715 Clear</button>\n }\n </div>\n }\n <div class=\"board-columns-wrapper\" [class.board-columns-nowrap]=\"!boardWrapColumns()\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\" [class.board-column-accented]=\"!!boardGroupColor(group)\"\n [style.--board-group-color]=\"boardGroupColor(group)\">\n @if (showBoardColumnHeader()) {\n <div class=\"column-header\">\n <!-- Render the group value through the same read-only cell renderer a\n data cell uses, so the grouped field's datatype formats itself\n (status/tag pills, dates, numbers) instead of printing raw text. -->\n @if (groupByColumn(); as gcol) {\n <span class=\"column-header-title column-header-title-cell\">\n <data-cell\n [eruGridStore]=\"gridStore\"\n [column]=\"gcol\"\n [columnDatatype]=\"gcol.datatype\"\n [columnName]=\"gcol.name\"\n [value]=\"group.title\"\n [id]=\"'board-group-' + group.id\"\n [fieldSize]=\"0\"\n [isEditable]=\"false\"\n [mode]=\"'board-group-header'\">\n </data-cell>\n </span>\n } @else {\n <span class=\"column-header-title\">{{ group.title }}</span>\n }\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n }\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"boardCardSlot\" class=\"board-column-body\"\n [style.height.px]=\"boardColumnBodyHeight(group)\"\n (scrolledIndexChange)=\"onBoardScrolledIndexChange($event, group)\">\n <div\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); templateCacheSize: 0\"\n class=\"board-card-container\"\n [class.selected]=\"isBoardCardActive(row)\"\n [class.show-row-lines]=\"showRowLines()\"\n [style.height.px]=\"boardCardOuterHeight\"\n [style.padding.px]=\"boardCardPadding\"\n [style.marginBottom.px]=\"boardCardGap\"\n [style.cursor]=\"cursorOnHover() || null\"\n (click)=\"emitRowSelect(row, 'board', group)\">\n <!-- Custom template when consumer provides boardCardTemplate; default card otherwise -->\n <ng-container\n *ngTemplateOutlet=\"boardCardTemplate ?? defaultBoardCard;\n context: { $implicit: row, columns: visibleBoardFields(), group: group }\">\n </ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n @if (group.isLoading) {\n <div class=\"board-ghost-card\">\n <div class=\"board-ghost-line\"></div>\n <div class=\"board-ghost-line board-ghost-line--short\"></div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n\n <!-- Table Mode Template -->\n <ng-template #excelDownloadIcon>\n <svg class=\"excel-download-icon\" title=\"Download Excel\" (click)=\"onExcelDownloadClick($event)\"\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"24px\" height=\"24px\">\n <path fill=\"#169154\" d=\"M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z\" />\n <path fill=\"#18482a\" d=\"M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z\" />\n <path fill=\"#0c8045\" d=\"M14 15.003H29V24.005000000000003H14z\" />\n <path fill=\"#17472a\" d=\"M14 24.005H29V33.055H14z\" />\n <g>\n <path fill=\"#29c27f\" d=\"M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z\" />\n <path fill=\"#27663f\" d=\"M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z\" />\n <path fill=\"#19ac65\" d=\"M29 15.003H44V24.005000000000003H29z\" />\n <path fill=\"#129652\" d=\"M29 24.005H44V33.055H29z\" />\n </g>\n <path fill=\"#0c7238\"\n d=\"M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z\" />\n <path fill=\"#fff\"\n d=\"M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z\" />\n </svg>\n </ng-template>\n @if(showExcelDownload() && !showGroupBar()) {\n <div class=\"excel-download-bar\">\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n </div>\n }\n <!-- Scrollable groups container \u2014 plain iteration avoids CDK fixed-height estimation errors -->\n <div #groupsScrollContainer class=\"groups-scroll-container\" (scroll)=\"onGroupsViewportScroll($event)\">\n\n @for (group of groups(); track trackByGroupFn($index, group); let i = $index) {\n <div class=\"group-container\"\n [attr.data-group-id]=\"group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id\">\n <!-- Combined sticky header with group info and table -->\n <div style=\"\n background:var(--grid-surface);\n position: sticky;\n top: 0;\n z-index: 115;\n \">\n @if(showGroupBar()) {\n <div class=\"group-header-row\">\n <div class=\"custom-collapse-header\" (click)=\"toggleGroupCollapse(group.id)\">\n <span class=\"collapse-arrow\" [ngClass]=\"{\n 'rotate-arrow': group.isExpanded,\n }\">\u25BC</span>\n <span class=\"f-12\">\n {{ group?.title || \"\" }}\n {{ group?.currentLoadedRows || 0 }} -\n {{ group?.totalRowCount || 0 }} rows...</span>\n @if(groupByField() && isSortable()) {\n <span class=\"group-sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'asc'\"\n (click)=\"onGroupSortToggle($event, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\"\n [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'desc'\"\n (click)=\"onGroupSortToggle($event, 'desc')\"></span>\n </span>\n </span>\n }\n </div>\n @if(i === 0 && showExcelDownload()) {\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n }\n </div>\n }\n\n @if(freezeHeader() && (group.isExpanded || !showGroupBar())) {\n <div #headerScroller class=\"header-shell\" [attr.data-group-id]=\"'header-shell-' + group.id\"\n [style]=\"'--table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <table class=\"eru-grid-table\" [class.freeze-header]=\"freezeHeader()\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n <!-- Grand Total row after sticky header (position: before) - only for first group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' && hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after sticky header (position: before) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'before' && hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n </table>\n </div>\n }\n </div>\n @if(group.isExpanded || !showGroupBar()) {\n <ng-container>\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"dataRowHeight()\" class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event, group)\" (scroll)=\"onTableBodyScroll($event)\"\n [style]=\"'--table-height: ' + getGroupContentHeight(group.id) + 'px; --table-min-height: ' + getGroupContentHeight(group.id) + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <div class=\"table-wrapper\">\n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\"\n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n @if(!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n }\n <!-- Grand Total row after normal header (position: before) - only for first group -->\n @if(!freezeHeader() && enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' &&\n hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after normal header (position: before) -->\n @if(!freezeHeader() && enableColumnSubtotals() && subtotalPositionColumn() === 'before' &&\n hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n <tbody>\n @if (columns(); as columnsList) {\n <!-- <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr> -->\n <!-- @if(getRowsForGroup(group.id).length > 0 && group.isExpanded) { -->\n <!-- *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id)(); \n trackBy: trackByRowFn; \n let i = index\" -->\n <!-- @for(row of getRowsForGroupSignal(group.id)(); track trackByRowFn($index, row); let i = $index) { -->\n <ng-container\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); trackBy: trackByRowFn; let i = index\">\n <tr class=\"row-item\" [attr.data-row-id]=\"i\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" (click)=\"emitRowSelect(row, 'table', group)\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input type=\"checkbox\" [checked]=\"isRowSelected(row?.entity_id)\"\n (change)=\"toggleRowSelection($event, row)\">\n </td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\" (click)=\"toggleRowExpand(row, i, $event)\">\n <mat-icon class=\"row-expand-icon\" [class.expanded]=\"isRowExpanded(row, i)\">chevron_right</mat-icon>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td #cell [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\"\n [matTooltipClass]=\"'error-message'\" [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\">\n <div class=\"cell-content\">\n <data-cell #datacell [personCardTemplate]=\"personCardTemplate\" [td]=cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\" [value]=\"(row?.['entity_data']?.[column.name] ?? row?.[column.name]) || ''\" [column]=\"column\"\n [mode]=\"mode()\" [isEditable]=\"isEditable() && column.editable !== false && column.editable !== 'false'\" [drillable]=\"column.enableDrilldown || false\"\n [id]=\"i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n </tr>\n @if(hasHiddenColumns() && isRowExpanded(row, i)) {\n <tr class=\"row-detail\">\n <td class=\"row-detail-cell\" [attr.colspan]=\"rowDetailColspan()\">\n <div class=\"row-detail-grid\">\n @for (hiddenCol of hiddenColumns(); track trackByColumnFn($index, hiddenCol)) {\n <div class=\"row-detail-field\">\n <span class=\"row-detail-label\">{{hiddenCol.label}}</span>\n <div class=\"row-detail-value\">\n <data-cell [fieldSize]=\"hiddenCol.field_size\" [columnDatatype]=\"hiddenCol.datatype\"\n [columnName]=\"hiddenCol.name\" [value]=\"(row?.['entity_data']?.[hiddenCol.name] ?? row?.[hiddenCol.name]) || ''\"\n [column]=\"hiddenCol\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [drillable]=\"hiddenCol.enableDrilldown || false\"\n [id]=\"'detail_' + i + '_' + hiddenCol.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-container>\n <!-- } -->\n <!-- } -->\n @if(group.isLoading && (group.isExpanded || !showGroupBar())) {\n @for(i of [].constructor(ghostRows()); let j = $index; track j) {\n <tr class=\"ghost-loading-row\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n </tr>\n }\n }\n <!-- <tr\n *ngIf=\"getRowsForGroup(group.id).length === 0 && !group.isExpanded\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr> -->\n <!-- Subtotal row at end of group (position: after) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'after' && hasSubtotalData(group)) {\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n }\n <!-- Grand Total row at end of group (position: after) - only for last group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'after' && hasGrandTotalData() && i ===\n groups().length - 1) {\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n }\n }\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container>\n }\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Pivot Table Header Template -->\n<ng-template #pivotTableHead>\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n @if (hasNestedHeaders()) {\n <ng-container>\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th [attr.colspan]=\"header.colspan\" [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"isResizablePivotHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header) || $any(header)\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\" [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\" [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor($any(header))\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n\n <data-cell [fieldSize]=\"header.field_size\" [columnDatatype]=\"header.dataType\" [columnName]=\"header.name\"\n [value]=\"header.label\" [column]=\"header\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\" [eruGridStore]=\"gridStore\" [row]=\"header\">\n </data-cell>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader($any(header)) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, $any(header))\">tune</mat-icon>\n }\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\"\n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\" [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\" [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor(column)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto;padding: 8px 6px\">\n <!-- Label and control laid out as a row: the label truncates, the\n control keeps its place. Left as a bare text node the long\n aggregation labels pushed the icon past the cell edge, where\n `overflow: hidden` clipped it out of sight entirely. -->\n <div class=\"pivot-header-content\">\n <!-- Deliberately not `.column-label`: that class carries the\n wrap-headers rule, which broke these labels onto one word per\n line. This header truncates, as it did before. -->\n <span class=\"pivot-header-label\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader(column) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n </div>\n </th>\n }\n </tr>\n </ng-container>\n }\n\n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n <tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\" [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"50\" [attr.xx]=\"i\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\" [column]=\"column\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n }\n </tbody>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Action column cell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One template for both column positions. With no `config.actions` set it\n falls back to the single more_horiz icon the column has always shown, so\n grids that only listen to the store's actionClick signal keep working.\n Context: { $implicit: Row, mode: 'table' | 'board', group?: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #actionCell let-row let-mode=\"mode\" let-group=\"group\">\n @if(!hasConfiguredActions()) {\n <mat-icon (click)=\"onActionClick($event, row, undefined, mode || 'table', group)\">more_horiz</mat-icon>\n } @else if(actionDisplayType() === 'kebab') {\n @if(visibleActionsFor(row).length > 0) {\n <mat-icon class=\"action-kebab\" [matMenuTriggerFor]=\"rowActionMenu\"\n [matMenuTriggerData]=\"{ row: row, mode: mode || 'table', group: group }\"\n (click)=\"$event.stopPropagation()\">more_vert</mat-icon>\n }\n } @else {\n <div class=\"action-icons\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <mat-icon class=\"action-icon\" [matTooltip]=\"action.action_name\" matTooltipPosition=\"above\"\n (click)=\"onActionClick($event, row, action, mode || 'table', group)\">{{action.action_icon || 'play_arrow'}}</mat-icon>\n }\n </div>\n }\n</ng-template>\n\n<!-- Kebab menu shared by every row; the row is passed through matMenuTriggerData. -->\n<mat-menu #rowActionMenu=\"matMenu\" class=\"eru-grid-action-menu\">\n <ng-template matMenuContent let-row=\"row\" let-mode=\"mode\" let-group=\"group\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <button mat-menu-item (click)=\"onActionClick($event, row, action, mode || 'table', group)\">\n <mat-icon>{{action.action_icon || 'play_arrow'}}</mat-icon>\n <span>{{action.action_name}}</span>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #tableColGroup>\n <colgroup>\n @if(gridStore.configuration().config.allowSelection) {\n <col style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n }\n @if(shouldShowActionColumn('before')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n @if(hasHiddenColumns()) {\n <col style=\"width: 40px !important; min-width: 40px !important; max-width: 40px !important;\">\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n @if(shouldShowActionColumn('after')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n </colgroup>\n</ng-template>\n\n\n<ng-template #tableHeader>\n\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n <tr>\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column column-header table-column-header\">\n <input type=\"checkbox\" [checked]=\"isAllGroupsSelected()\" (change)=\"toggleAllGroups($event)\">\n </th>\n }\n @if(shouldShowActionColumn('before')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n @if(hasHiddenColumns()) {\n <th class=\"row-expand-toggle column-header table-column-header\"></th>\n }\n @for (column of visibleColumns(); track trackByColumnFn(i, column); let i = $index) {\n <th [style.width.px]=\"column.field_size\" [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\" [index]=\"i\"\n [columnDraggable]=\"gridStore.isFeatureEnabled('columnReorderable') ? i : null\"\n [style.minWidth.px]=\"column.field_size\" class=\"column-header table-column-header\"\n [class.sortable-header]=\"isSortable()\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === column.name\"\n [class.sort-asc]=\"isSortable() && getSortDirection(column.name) === 'asc'\"\n [class.sort-desc]=\"isSortable() && getSortDirection(column.name) === 'desc'\">\n @if(gridStore.isFeatureEnabled('columnReorderable')) {\n <div class=\"column-drag-handle\"></div>\n }\n <span class=\"column-label\" [title]=\"column.tool_tip || column.description || ''\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\" title=\"Edit column\" (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n @if(isSortable()) {\n <span class=\"sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'asc'\"\n (click)=\"onSortColumn($event, column, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'desc'\"\n (click)=\"onSortColumn($event, column, 'desc')\"></span>\n </span>\n @if(getSortPriority(column.name) !== null && gridStore.sortColumns().length > 1) {\n <span class=\"sort-priority\">{{getSortPriority(column.name)}}</span>\n }\n </span>\n }\n </th>\n }\n @if(shouldShowActionColumn('after')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n </tr>\n </thead>\n</ng-template>\n\n<!-- Table Subtotal Row Template -->\n<ng-template #tableSubtotal let-group=\"group\">\n <tr class=\"subtotal-row\" [class.subtotal-bold]=\"subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"subTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"subtotal-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getSubtotalValue(group, column.name) === null) {\n <span class=\"subtotal-label\">{{subtotalLabel()}}</span>\n } @else {\n @if(getSubtotalValue(group, column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getSubtotalValue(group, column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'subtotal_' + group.id + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"group.subtotal\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- Table Grand Total Row Template -->\n<ng-template #tableGrandTotal>\n <tr class=\"grand-total-row\" [class.grand-total-bold]=\"grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"grandTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"grand-total-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getGrandTotalValue(column.name) === null) {\n <span class=\"grand-total-label\">Grand Total</span>\n } @else {\n @if(getGrandTotalValue(column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getGrandTotalValue(column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'grandtotal_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"gridStore.rowGrandTotal()\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Default board card template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Used when no boardCardTemplate is passed to <eru-grid>.\n Context: { $implicit: Row, columns: Field[], group: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #defaultBoardCard let-row let-columns=\"columns\" let-group=\"group\">\n <mat-card class=\"board-card\">\n <mat-card-content>\n @for (column of columns; track column.name) {\n @if ((row?.entity_data?.[column.name] ?? row?.[column.name]) !== undefined) {\n <div class=\"board-card-field\">\n <span class=\"board-field-label\">{{ column.label }}</span>\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [column]=\"column\"\n [value]=\"row?.entity_data?.[column.name] ?? row?.[column.name]\"\n [id]=\"row?.entity_id + '_' + column.name\"\n [eruGridStore]=\"gridStore\"\n [mode]=\"'board'\"\n [row]=\"row\">\n </data-cell>\n </div>\n }\n }\n </mat-card-content>\n <mat-card-actions align=\"end\">\n <button mat-icon-button (click)=\"onActionClick($event, row)\">\n <mat-icon>more_horiz</mat-icon>\n </button>\n </mat-card-actions>\n </mat-card>\n</ng-template>", styles: ["@charset \"UTF-8\";:root{--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6}:host,eru-grid{display:block!important;width:100%;height:100%;flex:1 1 0%;max-height:var(--grid-height, none);min-height:var(--grid-min-height, 120px);font-family:var(--grid-font-family);--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15);--grid-row-hover: var(--grid-surface-variant);--grid-row-selected: var(--grid-surface-container-high);--grid-zebra-odd: transparent;--grid-zebra-even: transparent;--grid-focus-ring: var(--grid-primary);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: var(--grid-font-size-caption);--grid-header-padding-x: 8px;--grid-header-padding-y: 12px;--grid-font-feature-numeric: normal;--grid-cell-padding-x: var(--grid-spacing-xs);--grid-cell-padding-y: var(--grid-spacing-xxs);--grid-tint-subtle: rgba(0, 0, 0, .025);--grid-tint-soft: rgba(0, 0, 0, .045);--grid-tint-strong: rgba(0, 0, 0, .08);--grid-radius-outer: 0;--grid-shadow-outer: none;--grid-divider-color: var(--grid-outline-variant);--grid-divider-width: 1px;--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-pill-radius: 999px;--grid-pill-padding-y: 3px;--grid-pill-padding-x: 10px;--grid-pill-font-size: 11px;--grid-pill-font-weight: 500;--grid-priority-dot-size: 8px;--grid-avatar-size: 24px;--grid-avatar-font-size: 10px;--grid-avatar-font-weight: 600;border-radius:var(--grid-radius-outer);box-shadow:var(--grid-shadow-outer)}eru-grid[data-preset=default]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .06em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-soft);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=modern]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: 13px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 16px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 12px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px}eru-grid[data-preset=compact]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 11px;--grid-header-padding-y: 4px;--grid-header-padding-x: 8px;--grid-cell-padding-y: 3px;--grid-cell-padding-x: 8px;--grid-font-size-body: 11px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 1px;--grid-pill-padding-x: 6px;--grid-pill-font-size: 10px}eru-grid[data-preset=bold]{--grid-header-bg: var(--grid-surface-container-high);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 700;--grid-header-text-transform: none;--grid-header-font-size: 13px;--grid-header-padding-y: 14px;--grid-header-padding-x: 12px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 12px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-strong);--grid-divider-width: 1px;--grid-radius-outer: 2px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=financial]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .08em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-zebra-odd: transparent;--grid-zebra-even: var(--grid-tint-subtle);--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=elevated]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 12px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 14px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 16px;--grid-shadow-outer: 0 1px 3px rgba(0, 0, 0, .06), 0 10px 28px rgba(0, 0, 0, .07);--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px;overflow:hidden}.group-container{padding-bottom:8px}.column-header.design-clickable .design-edit-icon{font-size:16px;width:16px;height:16px;margin-left:4px;opacity:.45;vertical-align:middle;cursor:pointer}.column-header.design-clickable:hover .design-edit-icon,.column-header.design-clickable .design-edit-icon:hover{opacity:1}.column-header.design-selected{background-color:var(--grid-primary-light, rgba(63, 81, 181, .12))}.pivot-column-header .pivot-header-content{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}.pivot-column-header .pivot-header-content .pivot-header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.pivot-column-header .pivot-header-content .design-edit-icon,.pivot-column-header .header-content .design-edit-icon{flex:0 0 auto}.pivot-column-header .header-content data-cell,.pivot-column-header .header-content data-cell *{color:inherit!important}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-min-height, 120px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);font-family:var(--grid-font-family)}.viewport{height:100%;min-height:300px;overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.groups-viewport{height:100%;min-height:300px}.groups-scroll-container{max-height:var(--grid-height, 600px);overflow-y:auto;overflow-x:hidden}.table-viewport{background-color:var(--grid-surface);height:var(--table-height, auto);min-height:var(--table-min-height, 100px);overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th{background-color:var(--grid-header-bg, var(--grid-surface-container))}thead.eru-wrap-headers th{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;height:auto}thead.eru-wrap-headers th .column-label,thead.eru-wrap-headers th .header-label{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;word-break:break-word;overflow-wrap:anywhere}.eru-grid-table tbody td{background-color:transparent}.eru-grid-table thead{background-color:var(--grid-header-bg, var(--grid-surface-container));transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{position:sticky!important;top:0!important;z-index:100!important}.eru-grid-table thead th{background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface));font-family:var(--grid-font-family);font-weight:var(--grid-header-font-weight);font-size:var(--grid-header-font-size)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.action-column{text-align:center;background-color:var(--grid-surface-container)}.action-column mat-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);cursor:pointer}.action-column mat-icon:hover{color:var(--grid-primary)}.action-column .action-icons{display:flex;align-items:center;justify-content:center;gap:6px;overflow-x:auto;scrollbar-width:none}.action-column .action-icons::-webkit-scrollbar{display:none}.action-column .action-icon{flex:0 0 auto}.eru-grid-action-menu .mat-mdc-menu-item mat-icon{margin-right:8px;font-size:18px;width:18px;height:18px;line-height:18px;color:var(--grid-on-surface-variant)}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{background-color:var(--grid-surface);transition:background-color .15s ease}.row-item:nth-child(odd){background-color:var(--grid-zebra-odd, var(--grid-surface))}.row-item:nth-child(2n){background-color:var(--grid-zebra-even, var(--grid-surface))}.row-item:hover{background-color:var(--grid-row-hover)}.required-toggle-row{background-color:var(--grid-surface-container, #f3edf7);border-bottom:1px solid var(--grid-outline-variant, #cac4d0)}.required-toggle-row .required-toggle-cell{padding:4px 8px!important;text-align:center;vertical-align:middle;position:relative}.required-toggle-row .required-toggle-cell .required-label{position:absolute;top:2px;left:4px;font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:400;text-transform:lowercase}.required-toggle-row .required-toggle-cell mat-checkbox{display:flex;justify-content:center;align-items:center}.table-column-header{padding:var(--grid-header-padding-y) var(--grid-header-padding-x)}.column-header{font-weight:var(--grid-header-font-weight);text-transform:var(--grid-header-text-transform);letter-spacing:var(--grid-header-letter-spacing);text-align:center!important;font-size:var(--grid-header-font-size);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface))}.column-header:hover{background-color:var(--grid-header-hover-bg, var(--grid-surface-container-high))}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.sortable-header{cursor:pointer}.sortable-header .column-label{flex:1}.sortable-header .sort-indicator{display:inline-flex;align-items:center;gap:2px;margin-left:4px;cursor:pointer;vertical-align:middle;opacity:0;transition:opacity .15s ease}.sortable-header .sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.sortable-header .sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.sortable-header .sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-active{opacity:1}.sortable-header .sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-priority{font-size:9px;font-weight:600;color:var(--grid-primary, #6750a4);line-height:1;min-width:12px;text-align:center}.sortable-header:hover .sort-indicator,.sortable-header.sort-asc .sort-indicator,.sortable-header.sort-desc .sort-indicator{opacity:1}.sortable-header:hover .sort-indicator .sort-tri:not(.sort-tri-active){opacity:.6}.sort-asc,.sort-desc{background-color:var(--grid-surface-container-low, rgba(103, 80, 164, .04))}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:transparent;color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);font-feature-settings:var(--grid-font-feature-numeric);padding:var(--grid-cell-padding-y) var(--grid-cell-padding-x)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines:not(.freeze-header){border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-divider-width, 1px) * 2);background-color:var(--grid-divider-color, var(--grid-outline, #e0e0e0));pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th,.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}.incremental-row-container .eru-grid-table.show-row-lines thead th,.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}@media(max-width:768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media(prefers-contrast:high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media(prefers-reduced-motion:reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .pivot-repeated-value .cell-content,.pivot-table .pivot-repeated-value .pivot-cell-content{visibility:hidden}.pivot-table .pivot-group-start.row-dimension-cell{border-top:1px solid var(--grid-outline, #79757f)}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table{table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:calc(var(--grid-data-row-height, 50px) - 2px);display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:calc(var(--grid-data-row-height, 50px) - 4px);display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:var(--grid-header-row-height, 40px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}.group-header-row{display:flex;align-items:center;justify-content:space-between;width:100%;padding-right:12px}.custom-collapse-header{background-color:var(--grid-surface-variant);padding:8px 20px;border-top-left-radius:12px;border-top-right-radius:12px;cursor:pointer;display:flex;width:fit-content;align-items:center;-webkit-user-select:none;user-select:none;min-width:200px;margin-bottom:10px;position:sticky;left:1px;z-index:116}.custom-collapse-header .collapse-arrow{display:inline-block;margin-right:8px;font-size:12px;color:var(--grid-on-surface-variant);transition:transform .2s ease;transform:rotate(0)}.custom-collapse-header .collapse-arrow.rotate-arrow{transform:rotate(270deg)}.custom-collapse-header .f-12{font-size:12px;color:var(--grid-on-surface)}.custom-collapse-header .group-sort-indicator{display:inline-flex;align-items:center;margin-left:8px}.custom-collapse-header .group-sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.custom-collapse-header .group-sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.custom-collapse-header .group-sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-active{opacity:1}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.excel-download-icon{cursor:pointer}.excel-download-icon:hover{opacity:.75}.excel-download-bar{display:flex;justify-content:flex-end;padding:4px 12px}.table-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .header-shell::-webkit-scrollbar{display:none}.table-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-mode .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.table-mode .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.table-mode .subtotal-row td:first-child{color:var(--grid-primary)}.table-mode .subtotal-row td.subtotal-cell{font-weight:500}.table-mode .subtotal-row td.subtotal-cell .subtotal-label{font-weight:600;color:var(--grid-primary)}.table-mode .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.table-mode .subtotal-row.subtotal-bold td{font-weight:600!important;font-style:normal!important}.table-mode .subtotal-row.subtotal-italic td{font-style:italic!important}.table-mode .subtotal-row.subtotal-italic td:first-child{font-weight:600!important}.table-mode .subtotal-row.subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.table-mode .subtotal-row.subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.table-mode .subtotal-row.subtotal-highlighted:hover,.table-mode .subtotal-row.subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row-shell{width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .subtotal-row-shell::-webkit-scrollbar{display:none}.board-mode-host{overflow:hidden;display:flex;flex-direction:column;max-height:var(--grid-height, 600px)}.board-mode-host .board-view-container{display:flex;flex-direction:column;flex:1;min-height:0}.board-mode-host .board-sort-bar{display:flex;align-items:center;gap:6px;padding:8px 16px;flex-shrink:0;border-bottom:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);overflow-x:auto}.board-mode-host .board-sort-bar .board-sort-label{font-size:12px;font-weight:500;color:var(--grid-on-surface-variant, #49454f);white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);color:var(--grid-on-surface, #1d1b20);font-size:12px;white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip-active{background:var(--grid-surface-container);border-color:var(--grid-outline, #79757f);color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-sort-bar .board-sort-chip-label{pointer-events:none}.board-mode-host .board-sort-bar .board-sort-chip-arrow{font-size:10px;line-height:1;cursor:pointer;padding:2px;border-radius:4px}.board-mode-host .board-sort-bar .board-sort-chip-arrow:hover{background:#00000014}.board-mode-host .board-sort-bar .board-sort-chip-priority{font-size:9px;font-weight:700;background:var(--grid-primary, #6750a4);color:var(--grid-on-primary, #ffffff);border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center}.board-mode-host .board-sort-bar .board-sort-chip-remove{font-size:10px;cursor:pointer;padding:2px;border-radius:4px;color:var(--grid-on-surface-variant, #49454f)}.board-mode-host .board-sort-bar .board-sort-chip-remove:hover{background:#00000014;color:var(--grid-error, #b3261e)}.board-mode-host .board-sort-bar .board-sort-add-btn{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px dashed var(--grid-outline-variant, #cac4d0);background:transparent;color:var(--grid-on-surface-variant, #49454f);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease,border-color .15s ease}.board-mode-host .board-sort-bar .board-sort-add-btn .board-sort-add-icon{font-size:14px;width:14px;height:14px}.board-mode-host .board-sort-bar .board-sort-add-btn:hover{background:var(--grid-surface-container-low, #f7f2fa);border-color:var(--grid-primary, #6750a4);color:var(--grid-primary, #6750a4)}.board-mode-host .board-sort-bar .board-sort-clear{display:inline-flex;align-items:center;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-error, #b3261e);background:transparent;color:var(--grid-error, #b3261e);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease}.board-mode-host .board-sort-bar .board-sort-clear:hover{background:#b3261e14}.board-mode-host .board-columns-wrapper{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr)));grid-auto-rows:auto;align-items:start;gap:16px;flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;align-content:start;justify-content:start}.board-mode-host .board-columns-wrapper.board-columns-nowrap{grid-auto-flow:column;grid-template-columns:none;grid-template-rows:auto;grid-auto-rows:auto;grid-auto-columns:minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr));overflow-x:auto;overflow-y:hidden}.board-mode-host .board-column{max-height:var(--board-column-height, 420px);min-width:0;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column.board-column-accented{border-top:3px solid var(--board-group-color, transparent)}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 14px;font-weight:600;flex-shrink:0}.board-mode-host .board-column .column-header:hover{background-color:transparent}.board-mode-host .board-column .column-header .column-header-title{font-size:15px;font-weight:700;letter-spacing:.2px;line-height:1.2;color:var(--grid-on-surface, #1d1b20);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.board-mode-host .board-column .column-header .column-header-title-cell{display:inline-flex;align-items:center;flex:1 1 auto;min-width:0;overflow:visible;text-overflow:clip}.board-mode-host .board-column .column-header .column-header-title-cell data-cell,.board-mode-host .board-column .column-header .column-header-title-cell .data-cell-component,.board-mode-host .board-column .column-header .column-header-title-cell .container{padding:0!important;margin:0!important;border:none!important;background:transparent!important;min-height:0!important;height:auto!important;width:auto!important;max-width:100%!important;overflow:visible!important}.board-mode-host .board-column .column-header .column-header-title-cell .status-display,.board-mode-host .board-column .column-header .column-header-title-cell .status-display-content,.board-mode-host .board-column .column-header .column-header-title-cell .status-text,.board-mode-host .board-column .column-header .column-header-title-cell .tag-display,.board-mode-host .board-column .column-header .column-header-title-cell .tag-text{max-width:none!important;overflow:visible!important;text-overflow:clip!important}.board-mode-host .board-column .column-header .column-header-count{font-size:10px;font-weight:600;color:var(--eru-board-count-color, var(--grid-on-surface-variant, #49454f));background:var(--eru-board-count-bg, var(--grid-surface-variant, #e7e0ec));border-radius:10px;padding:3px 10px;white-space:nowrap;flex-shrink:0}.board-mode-host .board-column-body{flex:0 1 auto;min-height:0}.board-mode-host .board-card-container{box-sizing:border-box;overflow:hidden;border-radius:8px;transition:background-color .15s ease,box-shadow .15s ease}.board-mode-host .board-card-container.show-row-lines{box-shadow:inset 0 0 0 var(--grid-divider-width, 1px) var(--grid-divider-color, var(--grid-outline, #e0e0e0))}.board-mode-host .board-card-container:hover{background-color:var(--eru-board-card-hover-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 8%, transparent))}.board-mode-host .board-card-container.selected{background-color:var(--eru-board-card-selected-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 14%, transparent));box-shadow:inset 0 0 0 2px var(--eru-board-card-selected-outline, var(--mat-sys-primary, #1976d2))}.board-mode-host .board-card{height:calc(100% - 8px);overflow:hidden;cursor:pointer}.board-mode-host .board-card mat-card-title{font-size:13px}.board-mode-host .board-card mat-card-subtitle{font-size:12px}.board-mode-host .board-card-field{display:flex;flex-direction:column;margin-bottom:4px}.board-mode-host .board-field-label{font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:500;text-transform:uppercase;letter-spacing:.5px}.board-mode-host .board-ghost-card{margin:8px;padding:16px;background:var(--grid-surface, #fef7ff);border-radius:8px;animation:board-pulse 1.5s ease-in-out infinite}.board-mode-host .board-ghost-line{height:12px;background:var(--grid-surface-variant, #e7e0ec);border-radius:4px;margin-bottom:8px}.board-mode-host .board-ghost-line--short{width:60%}@keyframes board-pulse{0%,to{opacity:1}50%{opacity:.5}}th.row-expand-toggle,td.row-expand-toggle{width:40px!important;min-width:40px!important;max-width:40px!important;padding:0!important;text-align:center;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box}.row-expand-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);transition:transform .15s ease-in-out}.row-expand-icon.expanded{transform:rotate(90deg)}.row-detail{background:var(--grid-surface-container)}.row-detail .row-detail-cell{padding:var(--grid-spacing-sm) var(--grid-spacing-md);border-bottom:1px solid var(--grid-outline-variant)}.row-detail .row-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--grid-spacing-sm) var(--grid-spacing-md)}.row-detail .row-detail-field{display:flex;flex-direction:column;gap:var(--grid-spacing-xxs);min-width:0}.row-detail .row-detail-label{font-size:var(--grid-font-size-caption);color:var(--grid-on-surface-variant);font-weight:500}.row-detail .row-detail-value{min-width:0}.row-detail .row-detail-value data-cell{display:block;width:100%}\n"] }]
14696
+ ], template: "<!-- <div style=\"background: #f0f0f0; font-size: 12px; border-bottom: 1px solid #ccc;\">\ncurrentPivotScrollIndex {{currentPivotScrollIndex()}} |\nfirstDataRowIndex {{firstDataRowIndex()}} |\nfirstTr {{firstTr}} |\nmaxDepth {{maxDepth()}}\n</div> -->\n<div class=\"incremental-row-container eru-grid\" #rowContainer [class.pivot-mode]=\"gridStore.isPivotMode()\"\n [class.table-mode]=\"!gridStore.isPivotMode() && !isBoardMode()\" [class.board-mode-host]=\"isBoardMode()\">\n <eru-column-design-panel></eru-column-design-panel>\n <!-- Pivot Mode Template -->\n @if (gridStore.isPivotMode()) {\n <ng-container>\n <div class=\"pivot-container\" style=\"display: flex; flex-direction: column; height: 100%;\"\n [style]=\"'--table-min-height: ' + getInitialMinHeightPx() + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <!-- Debug info for first visible row -->\n\n\n <div class=\"pivot-single-table\"\n style=\"height: 100%; width: 100%; overflow: hidden; display: flex; flex-direction: column;\">\n @if (freezeHeader()) {\n <div #headerScroller class=\"header-shell\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n @if(grandTotalPosition() === 'before' && freezeGrandTotal()) {\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n }\n </table>\n </div>\n }\n <!-- Virtual Scrolled Table Body -->\n <div>\n <cdk-virtual-scroll-viewport #vp [itemSize]=\"dataRowHeight()\" class=\"viewport pivot-viewport\"\n [class.apply-cdk-width]=\"applyCdkWidth()\" (scrolledIndexChange)=\"onPivotScroll($event)\"\n (scroll)=\"onBodyScroll($event)\" style=\"overflow: auto;\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <!-- Column Groups for consistent width -->\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n @if (!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"pivotTableHead\"></ng-container>\n }\n <!-- Table Body with Virtual Scrolling -->\n <tbody class=\"pivot-tbody\">\n\n <tr *cdkVirtualFor=\"let pivotRow of gridStore.pivotDisplayData(); \n trackBy: trackByPivotRowFn; \n let i = index\" class=\"pivot-row\" [class.subtotal-row]=\"pivotRow._isSubtotal\"\n [class.grand-total-row]=\"pivotRow._isGrandTotal\"\n [class.subtotal-bold]=\"pivotRow._isSubtotal && subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"pivotRow._isSubtotal && subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"pivotRow._isSubtotal && subTotalStyle() === 'highlighted'\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" [attr.data-pivot-row]=\"i\">\n @if ((!pivotRow._isGrandTotal && freezeGrandTotal() ) || (!freezeGrandTotal() )) {\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.pivot-repeated-value]=\"isRepeatedDimensionValue(i, column.name)\"\n [class.pivot-group-start]=\"isPivotGroupStart(i, column.name)\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [personCardTemplate]=\"personCardTemplate\" [class.aggregation]=\"!!column.aggregationFunction\" [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\" [value]=\"pivotRow[column.name]\"\n [column]=\"column\" [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\"\n [isEditable]=\"isEditable()\" [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\"\n [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n } @else {\n <td [style.height.px]=\"dataRowHeight()\" [attr.colspan]=\"getLeafColumns().length\"> </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n\n </div>\n @if (freezeGrandTotal() && grandTotalPosition() === 'after') {\n <div #gtScroller class=\"header-shell gt-shell\" [class.adjust-bottom]=\"!applyCdkWidth()\"\n [class.adjust-bottom-vs]=\"adjustScrollWidth()\">\n <table class=\"eru-grid-table pivot-table\"\n [style]=\"'width: auto; min-width: 100%; --table-total-width: ' + getInitialTotalWidth() + 'px'\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"pivotColGroup\"></ng-container>\n\n <ng-container *ngTemplateOutlet=\"pivotGrandTotal\"></ng-container>\n\n </table>\n </div>\n }\n\n\n </div>\n </div>\n </ng-container>\n } @else if (isBoardMode()) {\n <!-- Board Mode Template -->\n <div class=\"board-view-container\">\n @if(showSortBar()) {\n <div class=\"board-sort-bar\">\n <span class=\"board-sort-label\">Sort by:</span>\n @for (entry of gridStore.sortColumns(); track getFieldName(entry)) {\n <span class=\"board-sort-chip board-sort-chip-active\">\n <span class=\"board-sort-chip-label\">{{getColumnLabel(entry)}}</span>\n <span class=\"board-sort-chip-arrow\" (click)=\"onBoardSortChipToggle($event, entry)\">\n @if(!entry.startsWith('-')) { \u25B2 } @else { \u25BC }\n </span>\n @if(gridStore.sortColumns().length > 1) {\n <span class=\"board-sort-chip-priority\">{{getSortPriority(getFieldName(entry))}}</span>\n }\n <span class=\"board-sort-chip-remove\" (click)=\"onBoardSortChipRemove($event, entry)\">\u2715</span>\n </span>\n }\n <button class=\"board-sort-add-btn\" [matMenuTriggerFor]=\"sortFieldMenu\">\n <mat-icon class=\"board-sort-add-icon\">add</mat-icon> Add field\n </button>\n <mat-menu #sortFieldMenu=\"matMenu\" class=\"board-sort-menu\">\n @for (column of columns(); track column.name) {\n <button mat-menu-item (click)=\"onBoardSortFieldSelect(column)\"\n [disabled]=\"getSortDirection(column.name) !== null\">\n @if(getSortDirection(column.name) !== null) {\n <mat-icon>check</mat-icon>\n } @else {\n <mat-icon></mat-icon>\n }\n {{column.label}}\n </button>\n }\n </mat-menu>\n @if(gridStore.sortColumns().length > 0) {\n <button class=\"board-sort-clear\" (click)=\"onBoardSortClear()\">\u2715 Clear</button>\n }\n </div>\n }\n <div class=\"board-columns-wrapper\" [class.board-columns-nowrap]=\"!boardWrapColumns()\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\" [class.board-column-accented]=\"!!boardGroupColor(group)\"\n [style.--board-group-color]=\"boardGroupColor(group)\">\n @if (showBoardColumnHeader()) {\n <div class=\"column-header\">\n <!-- Render the group value through the same read-only cell renderer a\n data cell uses, so the grouped field's datatype formats itself\n (status/tag pills, dates, numbers) instead of printing raw text. -->\n @if (groupByColumn(); as gcol) {\n <span class=\"column-header-title column-header-title-cell\">\n <data-cell\n [eruGridStore]=\"gridStore\"\n [column]=\"gcol\"\n [columnDatatype]=\"gcol.datatype\"\n [columnName]=\"gcol.name\"\n [value]=\"group.title\"\n [id]=\"'board-group-' + group.id\"\n [fieldSize]=\"0\"\n [isEditable]=\"false\"\n [mode]=\"'board-group-header'\">\n </data-cell>\n </span>\n } @else {\n <span class=\"column-header-title\">{{ group.title }}</span>\n }\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n }\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"boardCardSlot\" class=\"board-column-body\"\n [style.height.px]=\"boardColumnBodyHeight(group)\"\n (scrolledIndexChange)=\"onBoardScrolledIndexChange($event, group)\">\n <div\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); templateCacheSize: 0\"\n class=\"board-card-container\"\n [class.selected]=\"isBoardCardActive(row)\"\n [class.show-row-lines]=\"showRowLines()\"\n [style.height.px]=\"boardCardOuterHeight\"\n [style.padding.px]=\"boardCardPadding\"\n [style.marginBottom.px]=\"boardCardGap\"\n [style.cursor]=\"cursorOnHover() || null\"\n (click)=\"emitRowSelect(row, 'board', group)\">\n <!-- Custom template when consumer provides boardCardTemplate; default card otherwise -->\n <ng-container\n *ngTemplateOutlet=\"boardCardTemplate ?? defaultBoardCard;\n context: { $implicit: row, columns: visibleBoardFields(), group: group }\">\n </ng-container>\n </div>\n </cdk-virtual-scroll-viewport>\n @if (group.isLoading) {\n <div class=\"board-ghost-card\">\n <div class=\"board-ghost-line\"></div>\n <div class=\"board-ghost-line board-ghost-line--short\"></div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n } @else {\n\n <!-- Table Mode Template -->\n <ng-template #excelDownloadIcon>\n <svg class=\"excel-download-icon\" title=\"Download Excel\" (click)=\"onExcelDownloadClick($event)\"\n xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" width=\"24px\" height=\"24px\">\n <path fill=\"#169154\" d=\"M29,6H15.744C14.781,6,14,6.781,14,7.744v7.259h15V6z\" />\n <path fill=\"#18482a\" d=\"M14,33.054v7.202C14,41.219,14.781,42,15.743,42H29v-8.946H14z\" />\n <path fill=\"#0c8045\" d=\"M14 15.003H29V24.005000000000003H14z\" />\n <path fill=\"#17472a\" d=\"M14 24.005H29V33.055H14z\" />\n <g>\n <path fill=\"#29c27f\" d=\"M42.256,6H29v9.003h15V7.744C44,6.781,43.219,6,42.256,6z\" />\n <path fill=\"#27663f\" d=\"M29,33.054V42h13.257C43.219,42,44,41.219,44,40.257v-7.202H29z\" />\n <path fill=\"#19ac65\" d=\"M29 15.003H44V24.005000000000003H29z\" />\n <path fill=\"#129652\" d=\"M29 24.005H44V33.055H29z\" />\n </g>\n <path fill=\"#0c7238\"\n d=\"M22.319,34H5.681C4.753,34,4,33.247,4,32.319V15.681C4,14.753,4.753,14,5.681,14h16.638 C23.247,14,24,14.753,24,15.681v16.638C24,33.247,23.247,34,22.319,34z\" />\n <path fill=\"#fff\"\n d=\"M9.807 19L12.193 19 14.129 22.754 16.175 19 18.404 19 15.333 24 18.474 29 16.123 29 14.013 25.07 11.912 29 9.526 29 12.719 23.982z\" />\n </svg>\n </ng-template>\n @if(showExcelDownload() && !showGroupBar()) {\n <div class=\"excel-download-bar\">\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n </div>\n }\n <!-- Scrollable groups container \u2014 plain iteration avoids CDK fixed-height estimation errors -->\n <div #groupsScrollContainer class=\"groups-scroll-container\" (scroll)=\"onGroupsViewportScroll($event)\">\n\n @for (group of groups(); track trackByGroupFn($index, group); let i = $index) {\n <div class=\"group-container\"\n [attr.data-group-id]=\"group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id\">\n <!-- Combined sticky header with group info and table -->\n <div style=\"\n background:var(--grid-surface);\n position: sticky;\n top: 0;\n z-index: 115;\n \">\n @if(showGroupBar()) {\n <div class=\"group-header-row\">\n <div class=\"custom-collapse-header\" (click)=\"toggleGroupCollapse(group.id)\">\n <span class=\"collapse-arrow\" [ngClass]=\"{\n 'rotate-arrow': group.isExpanded,\n }\">\u25BC</span>\n <span class=\"f-12\">\n {{ group?.title || \"\" }}\n {{ group?.currentLoadedRows || 0 }} -\n {{ group?.totalRowCount || 0 }} rows...</span>\n @if(groupByField() && isSortable()) {\n <span class=\"group-sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'asc'\"\n (click)=\"onGroupSortToggle($event, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\"\n [class.sort-tri-active]=\"getSortDirection(groupByField()!) === 'desc'\"\n (click)=\"onGroupSortToggle($event, 'desc')\"></span>\n </span>\n </span>\n }\n </div>\n @if(i === 0 && showExcelDownload()) {\n <ng-container *ngTemplateOutlet=\"excelDownloadIcon\"></ng-container>\n }\n </div>\n }\n\n @if(freezeHeader() && (group.isExpanded || !showGroupBar())) {\n <div #headerScroller class=\"header-shell\" [attr.data-group-id]=\"'header-shell-' + group.id\"\n [style]=\"'--table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <table class=\"eru-grid-table\" [class.freeze-header]=\"freezeHeader()\"\n [class.show-column-lines]=\"showColumnLines()\" [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n <!-- Grand Total row after sticky header (position: before) - only for first group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' && hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after sticky header (position: before) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'before' && hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n </table>\n </div>\n }\n </div>\n @if(group.isExpanded || !showGroupBar()) {\n <ng-container>\n <cdk-virtual-scroll-viewport [attr.data-group-id]=\"group.id\" [itemSize]=\"dataRowHeight()\" class=\"viewport table-viewport\"\n (scrolledIndexChange)=\"onScroll($event, group)\" (scroll)=\"onTableBodyScroll($event)\"\n [style]=\"'--table-height: ' + getGroupContentHeight(group.id) + 'px; --table-min-height: ' + getGroupContentHeight(group.id) + 'px; --table-total-width: ' + getInitialTotalWidth() + 'px'\">\n <div class=\"table-wrapper\">\n <table class=\"eru-grid-table\" [class.show-column-lines]=\"showColumnLines()\"\n [class.show-row-lines]=\"showRowLines()\">\n <ng-container *ngTemplateOutlet=\"tableColGroup\"></ng-container>\n @if(!freezeHeader()) {\n <ng-container *ngTemplateOutlet=\"tableHeader\"></ng-container>\n }\n <!-- Grand Total row after normal header (position: before) - only for first group -->\n @if(!freezeHeader() && enableColumnGrandTotal() && grandTotalPositionColumn() === 'before' &&\n hasGrandTotalData() && i === 0) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n </tbody>\n }\n <!-- Subtotal row after normal header (position: before) -->\n @if(!freezeHeader() && enableColumnSubtotals() && subtotalPositionColumn() === 'before' &&\n hasSubtotalData(group)) {\n <tbody>\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n </tbody>\n }\n <tbody>\n @if (columns(); as columnsList) {\n <!-- <tr *ngIf=\"groupItem.type === 'table-header' && groups().length > 1\" style=\"background:#fafafa\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column\" style=\"text-align: center;\">\n <input\n type=\"checkbox\"\n [checked]=\"isGroupSelected(groupItem.group?.id || '')\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGroupSelection($event, groupItem.group?.id || '')\"\n >\n </th>\n }\n <th *ngFor=\"let column of columns(); trackBy: trackByColumnFn;let i =index\"\n style=\"text-align: center;\"\n [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"true\"\n [columnConfig]=\"column\"\n [columnDraggable]=\"i\"\n class=\"column-header\">\n <div class=\"column-drag-handle\"></div>\n {{column.label}} {{column.symbol}}\n </th>\n </tr> -->\n <!-- @if(getRowsForGroup(group.id).length > 0 && group.isExpanded) { -->\n <!-- *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id)(); \n trackBy: trackByRowFn; \n let i = index\" -->\n <!-- @for(row of getRowsForGroupSignal(group.id)(); track trackByRowFn($index, row); let i = $index) { -->\n <ng-container\n *cdkVirtualFor=\"let row of getRowsForGroupSignal(group.id === null || group.id === undefined ? '__NULL_GROUP__' : group.id)(); trackBy: trackByRowFn; let i = index\">\n <tr class=\"row-item\" [attr.data-row-id]=\"i\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\" [style.cursor]=\"cursorOnHover() || null\" (click)=\"emitRowSelect(row, 'table', group)\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\" style=\"text-align: center;\">\n <input type=\"checkbox\" [checked]=\"isRowSelected(row?.entity_id)\"\n (change)=\"toggleRowSelection($event, row)\">\n </td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\" (click)=\"toggleRowExpand(row, i, $event)\">\n <mat-icon class=\"row-expand-icon\" [class.expanded]=\"isRowExpanded(row, i)\">chevron_right</mat-icon>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td #cell [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"data-cell\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\"\n [matTooltipClass]=\"'error-message'\" [matTooltip]=\"datacell.error()?'Error: ' + datacell.error():''\"\n matTooltipPosition=\"below\">\n <div class=\"cell-content\">\n <data-cell #datacell [personCardTemplate]=\"personCardTemplate\" [td]=cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\" [value]=\"(row?.['entity_data']?.[column.name] ?? row?.[column.name]) || ''\" [column]=\"column\"\n [mode]=\"mode()\" [isEditable]=\"isEditable() && column.editable !== false && column.editable !== 'false'\" [drillable]=\"column.enableDrilldown || false\"\n [id]=\"i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <ng-container\n *ngTemplateOutlet=\"actionCell; context: { $implicit: row, mode: 'table', group: group }\"></ng-container>\n </td>\n }\n </tr>\n @if(hasHiddenColumns() && isRowExpanded(row, i)) {\n <tr class=\"row-detail\">\n <td class=\"row-detail-cell\" [attr.colspan]=\"rowDetailColspan()\">\n <div class=\"row-detail-grid\">\n @for (hiddenCol of hiddenColumns(); track trackByColumnFn($index, hiddenCol)) {\n <div class=\"row-detail-field\">\n <span class=\"row-detail-label\">{{hiddenCol.label}}</span>\n <div class=\"row-detail-value\">\n <data-cell [fieldSize]=\"hiddenCol.field_size\" [columnDatatype]=\"hiddenCol.datatype\"\n [columnName]=\"hiddenCol.name\" [value]=\"(row?.['entity_data']?.[hiddenCol.name] ?? row?.[hiddenCol.name]) || ''\"\n [column]=\"hiddenCol\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [drillable]=\"hiddenCol.enableDrilldown || false\"\n [id]=\"'detail_' + i + '_' + hiddenCol.name\" [eruGridStore]=\"gridStore\" [row]=\"row\"></data-cell>\n </div>\n </div>\n }\n </div>\n </td>\n </tr>\n }\n </ng-container>\n <!-- } -->\n <!-- } -->\n @if(group.isLoading && (group.isExpanded || !showGroupBar())) {\n @for(i of [].constructor(ghostRows()); let j = $index; track j) {\n <tr class=\"ghost-loading-row\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n class=\"ghost-cell-container\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column ghost-cell-container\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">\n <div class=\"ghost-cell\"></div>\n </td>\n }\n </tr>\n }\n }\n <!-- <tr\n *ngIf=\"getRowsForGroup(group.id).length === 0 && !group.isExpanded\"\n class=\"group-separator\"\n >\n <td [attr.colspan]=\"groupSeperatorColSpan()\" class=\"separator-cell\"></td>\n </tr> -->\n <!-- Subtotal row at end of group (position: after) -->\n @if(enableColumnSubtotals() && subtotalPositionColumn() === 'after' && hasSubtotalData(group)) {\n <ng-container *ngTemplateOutlet=\"tableSubtotal; context: { group: group }\"></ng-container>\n }\n <!-- Grand Total row at end of group (position: after) - only for last group -->\n @if(enableColumnGrandTotal() && grandTotalPositionColumn() === 'after' && hasGrandTotalData() && i ===\n groups().length - 1) {\n <ng-container *ngTemplateOutlet=\"tableGrandTotal\"></ng-container>\n }\n }\n </tbody>\n </table>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container>\n }\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Pivot Table Header Template -->\n<ng-template #pivotTableHead>\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n @if (hasNestedHeaders()) {\n <ng-container>\n @for (headerRow of getHeaderRows(); track headerRow; let rowIndex = $index) {\n <tr class=\"pivot-header pivot-header-container\" [class.pivot-header-level]=\"'level-' + rowIndex\">\n @for (header of headerRow; track trackByHeaderFn($index, header); let colIndex = $index) {\n <th [attr.colspan]=\"header.colspan\" [attr.rowspan]=\"header.rowspan\"\n [resizeColumn]=\"isResizablePivotHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header) || $any(header)\"\n class=\"column-header pivot-column-header nested-header\"\n [class.row-dimension-header]=\"isRowDimensionHeader(header)\"\n [class.column-dimension-header]=\"!isRowDimensionHeader(header)\" [class.expanded]=\"header.isExpanded\"\n [class.collapsed]=\"!header.isExpanded\" [class.sticky-column]=\"isStickyColumn(header.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor($any(header))\"\n [style.position]=\"isStickyColumn(header.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(header.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(header.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto; padding: 8px 6px;\">\n <div class=\"header-content\">\n\n <data-cell [fieldSize]=\"header.field_size\" [columnDatatype]=\"header.dataType\" [columnName]=\"header.name\"\n [value]=\"header.label\" [column]=\"header\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"header.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + $index + '_' + header.name\" [eruGridStore]=\"gridStore\" [row]=\"header\">\n </data-cell>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader($any(header)) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, $any(header))\">tune</mat-icon>\n }\n <!-- <span class=\"header-label header-wrap-text\">{{header.label}}</span> -->\n <!-- <button *ngIf=\"!isRowDimensionHeader(header)\"\n class=\"collapse-toggle-btn\"\n [title]=\"header.isExpanded ? 'Collapse group' : 'Expand group'\"\n (click)=\"toggleColumnGroup(header.groupKey)\"\n type=\"button\">\n <span class=\"collapse-icon\">+</span>\n </button> -->\n </div>\n </th>\n }\n </tr>\n }\n </ng-container>\n } @else {\n <!-- Simple header fallback -->\n <ng-container>\n <tr class=\"pivot-header\" [class.freeze-header-enabled]=\"freezeHeader()\">\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <th [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\"\n [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\" [columnConfig]=\"column\"\n class=\"column-header pivot-column-header\" [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === designTargetFor(column)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 100 : 1\"\n [style.min-height.px]=\"headerRowHeight()\" style=\"height: auto;padding: 8px 6px\">\n <!-- Label and control laid out as a row: the label truncates, the\n control keeps its place. Left as a bare text node the long\n aggregation labels pushed the icon past the cell edge, where\n `overflow: hidden` clipped it out of sight entirely. -->\n <div class=\"pivot-header-content\">\n <!-- Deliberately not `.column-label`: that class carries the\n wrap-headers rule, which broke these labels onto one word per\n line. This header truncates, as it did before. -->\n <span class=\"pivot-header-label\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\"\n [title]=\"isAggregationHeader(column) ? 'Edit aggregation' : 'Edit column'\"\n (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n </div>\n </th>\n }\n </tr>\n </ng-container>\n }\n\n </thead>\n</ng-template>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #pivotColGroup>\n <colgroup>\n @for (column of getLeafColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n </colgroup>\n</ng-template>\n\n<ng-template #pivotGrandTotal>\n <tbody class=\"pivot-tbody\">\n @for (pivotRow of gridStore.pivotGrandTotalData(); track trackByPivotRowFn($index, pivotRow); let i = $index) {\n <tr class=\"pivot-row grand-total-row\"\n [class.grand-total-bold]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"pivotRow._isGrandTotal && grandTotalStyle() === 'highlighted'\"\n [style.height.px]=\"50\" [attr.data-pivot-row]=\"i\">\n <!-- <td colspan=\"20\">{{pivotRow | json}}</td> -->\n @for (column of getLeafColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [attr.rowspan]=\"getEffectiveRowspan(i, column.name)\" [style.width.px]=\"column.field_size\"\n [style.minWidth.px]=\"column.field_size\" class=\"pivot-cell\"\n [class.row-dimension-cell]=\"isRowDimensionColumn(column.name)\"\n [class.column-dimension-cell]=\"!isRowDimensionColumn(column.name)\"\n [class.aggregated-value]=\"!isRowDimensionColumn(column.name) && column.datatype === 'number'\"\n [class.rowspan-cell]=\"getEffectiveRowspan(i, column.name) || 1 > 1\"\n [class.sticky-column]=\"isStickyColumn(column.name, colIndex)\"\n [style.position]=\"isStickyColumn(column.name, colIndex) ? 'sticky' : 'static'\"\n [style.left.px]=\"getStickyColumnLeft(column.name, colIndex)\"\n [style.z-index]=\"isStickyColumn(column.name, colIndex) ? 99 : 1\" [style.height.px]=\"50\" [attr.xx]=\"i\">\n <div class=\"cell-content pivot-cell-content\">\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getEffectiveCellValue(i,column.name, pivotRow)\" [column]=\"column\" [frozenGrandTotalCell]=\"true\"\n [drillable]=\"column.enableDrilldown || false\" [mode]=\"mode()\" [isEditable]=\"isEditable()\"\n [id]=\"'pivot_' + i + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"pivotRow\">\n </data-cell>\n </div>\n </td>\n }\n </tr>\n }\n </tbody>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Action column cell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n One template for both column positions. With no `config.actions` set it\n falls back to the single more_horiz icon the column has always shown, so\n grids that only listen to the store's actionClick signal keep working.\n Context: { $implicit: Row, mode: 'table' | 'board', group?: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #actionCell let-row let-mode=\"mode\" let-group=\"group\">\n @if(!hasConfiguredActions()) {\n <mat-icon (click)=\"onActionClick($event, row, undefined, mode || 'table', group)\">more_horiz</mat-icon>\n } @else if(actionDisplayType() === 'kebab') {\n @if(visibleActionsFor(row).length > 0) {\n <mat-icon class=\"action-kebab\" [matMenuTriggerFor]=\"rowActionMenu\"\n [matMenuTriggerData]=\"{ row: row, mode: mode || 'table', group: group }\"\n (click)=\"$event.stopPropagation()\">more_vert</mat-icon>\n }\n } @else {\n <div class=\"action-icons\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <mat-icon class=\"action-icon\" [matTooltip]=\"action.action_name\" matTooltipPosition=\"above\"\n (click)=\"onActionClick($event, row, action, mode || 'table', group)\">{{action.action_icon || 'play_arrow'}}</mat-icon>\n }\n </div>\n }\n</ng-template>\n\n<!-- Kebab menu shared by every row; the row is passed through matMenuTriggerData. -->\n<mat-menu #rowActionMenu=\"matMenu\" class=\"eru-grid-action-menu\">\n <ng-template matMenuContent let-row=\"row\" let-mode=\"mode\" let-group=\"group\">\n @for(action of visibleActionsFor(row); track action.action_name) {\n <button mat-menu-item (click)=\"onActionClick($event, row, action, mode || 'table', group)\">\n <mat-icon>{{action.action_icon || 'play_arrow'}}</mat-icon>\n <span>{{action.action_name}}</span>\n </button>\n }\n </ng-template>\n</mat-menu>\n\n<!-- Column Group Template for consistent column widths -->\n<ng-template #tableColGroup>\n <colgroup>\n @if(gridStore.configuration().config.allowSelection) {\n <col style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n }\n @if(shouldShowActionColumn('before')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n @if(hasHiddenColumns()) {\n <col style=\"width: 40px !important; min-width: 40px !important; max-width: 40px !important;\">\n }\n @for (column of visibleColumns(); track trackByColumnFn($index, column)) {\n <col\n [style]=\"'width: ' + column.field_size + 'px !important; min-width: ' + column.field_size + 'px !important; max-width: ' + column.field_size + 'px !important; --col-width: ' + column.field_size + 'px'\">\n }\n @if(shouldShowActionColumn('after')) {\n <col\n [style]=\"'width: ' + actionColumnWidth() + 'px !important; min-width: ' + actionColumnWidth() + 'px !important; max-width: ' + actionColumnWidth() + 'px !important;'\">\n }\n </colgroup>\n</ng-template>\n\n\n<ng-template #tableHeader>\n\n <thead [class.eru-wrap-headers]=\"wrapHeaders()\">\n <!-- headerRowHeight rides on the row, not the cells: `thead.eru-wrap-headers\n th { height: auto }` outranks any class-level height we could put on a\n th, which is why a configured header height was ignored while data rows\n (inline height on tr.row-item) honoured theirs. On a table row `height`\n is a minimum, so a wrapped two-line header still grows past it. -->\n <tr [style.height.px]=\"headerRowHeight()\" [style.minHeight.px]=\"headerRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <th class=\"checkbox-column column-header table-column-header\">\n <input type=\"checkbox\" [checked]=\"isAllGroupsSelected()\" (change)=\"toggleAllGroups($event)\">\n </th>\n }\n @if(shouldShowActionColumn('before')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n @if(hasHiddenColumns()) {\n <th class=\"row-expand-toggle column-header table-column-header\"></th>\n }\n @for (column of visibleColumns(); track trackByColumnFn(i, column); let i = $index) {\n <th [style.width.px]=\"column.field_size\" [resizeColumn]=\"gridStore.isFeatureEnabled('columnResizable')\"\n [columnConfig]=\"column\" [index]=\"i\"\n [columnDraggable]=\"gridStore.isFeatureEnabled('columnReorderable') ? i : null\"\n [style.minWidth.px]=\"column.field_size\" class=\"column-header table-column-header\"\n [class.sortable-header]=\"isSortable()\"\n [class.design-clickable]=\"isDesignMode()\"\n [class.design-selected]=\"isDesignMode() && gridStore.selectedDesignColumn() === column.name\"\n [class.sort-asc]=\"isSortable() && getSortDirection(column.name) === 'asc'\"\n [class.sort-desc]=\"isSortable() && getSortDirection(column.name) === 'desc'\">\n @if(gridStore.isFeatureEnabled('columnReorderable')) {\n <div class=\"column-drag-handle\"></div>\n }\n <span class=\"column-label\" [title]=\"column.tool_tip || column.description || ''\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\" title=\"Edit column\" (click)=\"onHeaderDesignClick($event, column)\">tune</mat-icon>\n }\n @if(isSortable()) {\n <span class=\"sort-indicator\">\n <span class=\"sort-triangles\">\n <span class=\"sort-tri sort-tri-up\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'asc'\"\n (click)=\"onSortColumn($event, column, 'asc')\"></span>\n <span class=\"sort-tri sort-tri-down\" [class.sort-tri-active]=\"getSortDirection(column.name) === 'desc'\"\n (click)=\"onSortColumn($event, column, 'desc')\"></span>\n </span>\n @if(getSortPriority(column.name) !== null && gridStore.sortColumns().length > 1) {\n <span class=\"sort-priority\">{{getSortPriority(column.name)}}</span>\n }\n </span>\n }\n </th>\n }\n @if(shouldShowActionColumn('after')) {\n <th class=\"action-column column-header table-column-header\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\">Action</th>\n }\n </tr>\n </thead>\n</ng-template>\n\n<!-- Table Subtotal Row Template -->\n<ng-template #tableSubtotal let-group=\"group\">\n <tr class=\"subtotal-row\" [class.subtotal-bold]=\"subTotalStyle() === 'bold'\"\n [class.subtotal-italic]=\"subTotalStyle() === 'italic'\"\n [class.subtotal-highlighted]=\"subTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"subtotal-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getSubtotalValue(group, column.name) === null) {\n <span class=\"subtotal-label\">{{subtotalLabel()}}</span>\n } @else {\n @if(getSubtotalValue(group, column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getSubtotalValue(group, column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'subtotal_' + group.id + '_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"group.subtotal\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- Table Grand Total Row Template -->\n<ng-template #tableGrandTotal>\n <tr class=\"grand-total-row\" [class.grand-total-bold]=\"grandTotalStyle() === 'bold'\"\n [class.grand-total-italic]=\"grandTotalStyle() === 'italic'\"\n [class.grand-total-highlighted]=\"grandTotalStyle() === 'highlighted'\" [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n @if(gridStore.configuration().config.allowSelection) {\n <td class=\"checkbox-column\"></td>\n }\n @if(shouldShowActionColumn('before')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n @if(hasHiddenColumns()) {\n <td class=\"row-expand-toggle\"></td>\n }\n @for(column of visibleColumns(); track trackByColumnFn($index, column); let colIndex = $index) {\n <td [style.width.px]=\"column.field_size\" [style.minWidth.px]=\"column.field_size\" class=\"grand-total-cell\"\n [style.height.px]=\"dataRowHeight()\" [style.minHeight.px]=\"dataRowHeight()\">\n <div class=\"cell-content\">\n @if(colIndex === 0 && getGrandTotalValue(column.name) === null) {\n <span class=\"grand-total-label\">Grand Total</span>\n } @else {\n @if(getGrandTotalValue(column.name) !== null) {\n <data-cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\" [columnName]=\"column.name\"\n [value]=\"getGrandTotalValue(column.name)\" [column]=\"column\" [mode]=\"mode()\" [isEditable]=\"false\"\n [id]=\"'grandtotal_' + column.name\" [eruGridStore]=\"gridStore\" [row]=\"gridStore.rowGrandTotal()\">\n </data-cell>\n }\n }\n </div>\n </td>\n }\n @if(shouldShowActionColumn('after')) {\n <td class=\"action-column\" [style.width.px]=\"actionColumnWidth()\"\n [style.minWidth.px]=\"actionColumnWidth()\" [style.maxWidth.px]=\"actionColumnWidth()\"></td>\n }\n </tr>\n</ng-template>\n\n<!-- \u2500\u2500\u2500 Default board card template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Used when no boardCardTemplate is passed to <eru-grid>.\n Context: { $implicit: Row, columns: Field[], group: RowGroup }\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<ng-template #defaultBoardCard let-row let-columns=\"columns\" let-group=\"group\">\n <mat-card class=\"board-card\">\n <mat-card-content>\n @for (column of columns; track column.name) {\n @if ((row?.entity_data?.[column.name] ?? row?.[column.name]) !== undefined) {\n <div class=\"board-card-field\">\n <span class=\"board-field-label\">{{ column.label }}</span>\n <data-cell\n [fieldSize]=\"column.field_size\"\n [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\"\n [column]=\"column\"\n [value]=\"row?.entity_data?.[column.name] ?? row?.[column.name]\"\n [id]=\"row?.entity_id + '_' + column.name\"\n [eruGridStore]=\"gridStore\"\n [mode]=\"'board'\"\n [row]=\"row\">\n </data-cell>\n </div>\n }\n }\n </mat-card-content>\n <mat-card-actions align=\"end\">\n <button mat-icon-button (click)=\"onActionClick($event, row)\">\n <mat-icon>more_horiz</mat-icon>\n </button>\n </mat-card-actions>\n </mat-card>\n</ng-template>", styles: ["@charset \"UTF-8\";:root{--grid-primary: #6750a4;--grid-on-primary: #ffffff;--grid-surface: #fef7ff;--grid-surface-variant: #e7e0ec;--grid-surface-container: #f3edf7;--grid-surface-container-high: #ede7f0;--grid-on-surface: #1d1b20;--grid-on-surface-variant: #49454f;--grid-outline: #79757f;--grid-outline-variant: #cac4d0;--grid-error: #ba1a1a;--grid-error-container: #ffdad6}:host,eru-grid{display:block!important;width:100%;height:100%;flex:1 1 0%;max-height:var(--grid-height, none);min-height:var(--grid-min-height, 120px);font-family:var(--grid-font-family);--grid-font-family: \"Poppins\", \"Roboto\", -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;--grid-font-size-body: 12px;--grid-font-size-caption: 12px !important;--grid-line-height-body: 1;--grid-aggregation-text-align: right;--grid-number-text-align: right;--grid-spacing-xxs: 2px;--grid-spacing-xs: 4px;--grid-spacing-sm: 8px;--grid-spacing-md: 16px;--grid-spacing-lg: 24px;--grid-border-radius: 4px;--grid-elevation-1: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 1px 3px 1px rgba(0, 0, 0, .15);--grid-elevation-2: 0px 1px 2px 0px rgba(0, 0, 0, .3), 0px 2px 6px 2px rgba(0, 0, 0, .15);--grid-row-hover: var(--grid-surface-variant);--grid-row-selected: var(--grid-surface-container-high);--grid-zebra-odd: transparent;--grid-zebra-even: transparent;--grid-focus-ring: var(--grid-primary);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: var(--grid-font-size-caption);--grid-header-padding-x: 8px;--grid-header-padding-y: 12px;--grid-font-feature-numeric: normal;--grid-cell-padding-x: var(--grid-spacing-xs);--grid-cell-padding-y: var(--grid-spacing-xxs);--grid-tint-subtle: rgba(0, 0, 0, .025);--grid-tint-soft: rgba(0, 0, 0, .045);--grid-tint-strong: rgba(0, 0, 0, .08);--grid-radius-outer: 0;--grid-shadow-outer: none;--grid-divider-color: var(--grid-outline-variant);--grid-divider-width: 1px;--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-pill-radius: 999px;--grid-pill-padding-y: 3px;--grid-pill-padding-x: 10px;--grid-pill-font-size: 11px;--grid-pill-font-weight: 500;--grid-priority-dot-size: 8px;--grid-avatar-size: 24px;--grid-avatar-font-size: 10px;--grid-avatar-font-weight: 600;border-radius:var(--grid-radius-outer);box-shadow:var(--grid-shadow-outer)}eru-grid[data-preset=default]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .06em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-soft);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=modern]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: none;--grid-header-letter-spacing: normal;--grid-header-font-size: 13px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 16px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 12px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px}eru-grid[data-preset=compact]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 11px;--grid-header-padding-y: 4px;--grid-header-padding-x: 8px;--grid-cell-padding-y: 3px;--grid-cell-padding-x: 8px;--grid-font-size-body: 11px;--grid-row-hover: var(--grid-tint-subtle);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 1px;--grid-pill-padding-x: 6px;--grid-pill-font-size: 10px}eru-grid[data-preset=bold]{--grid-header-bg: var(--grid-surface-container-high);--grid-header-color: var(--grid-on-surface);--grid-header-font-weight: 700;--grid-header-text-transform: none;--grid-header-font-size: 13px;--grid-header-padding-y: 14px;--grid-header-padding-x: 12px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 12px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-strong);--grid-divider-width: 1px;--grid-radius-outer: 2px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=financial]{--grid-header-bg: var(--grid-surface-container);--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 500;--grid-header-text-transform: uppercase;--grid-header-letter-spacing: .08em;--grid-header-font-size: 11px;--grid-header-padding-y: 12px;--grid-header-padding-x: 14px;--grid-cell-padding-y: 10px;--grid-cell-padding-x: 14px;--grid-zebra-odd: transparent;--grid-zebra-even: var(--grid-tint-subtle);--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-font-feature-numeric: \"tnum\"}eru-grid[data-preset=elevated]{--grid-header-bg: transparent;--grid-header-color: var(--grid-on-surface-variant);--grid-header-font-weight: 600;--grid-header-text-transform: none;--grid-header-font-size: 12px;--grid-header-padding-y: 16px;--grid-header-padding-x: 18px;--grid-cell-padding-y: 14px;--grid-cell-padding-x: 18px;--grid-row-hover: var(--grid-tint-soft);--grid-divider-color: var(--grid-tint-subtle);--grid-divider-width: 1px;--grid-radius-outer: 16px;--grid-shadow-outer: 0 1px 3px rgba(0, 0, 0, .06), 0 10px 28px rgba(0, 0, 0, .07);--grid-font-feature-numeric: \"tnum\";--grid-pill-padding-y: 4px;--grid-pill-padding-x: 12px;overflow:hidden}.group-container{padding-bottom:8px}.column-header.design-clickable .design-edit-icon{font-size:16px;width:16px;height:16px;margin-left:4px;opacity:.45;vertical-align:middle;cursor:pointer}.column-header.design-clickable:hover .design-edit-icon,.column-header.design-clickable .design-edit-icon:hover{opacity:1}.column-header.design-selected{background-color:var(--grid-primary-light, rgba(63, 81, 181, .12))}.pivot-column-header .pivot-header-content{display:flex;align-items:center;justify-content:center;gap:4px;min-width:0}.pivot-column-header .pivot-header-content .pivot-header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.pivot-column-header .pivot-header-content .design-edit-icon,.pivot-column-header .header-content .design-edit-icon{flex:0 0 auto}.pivot-column-header .header-content data-cell,.pivot-column-header .header-content data-cell *{color:inherit!important}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-min-height, 120px);max-height:none;overflow:auto;position:relative;background-color:var(--grid-surface);border-radius:var(--grid-border-radius);font-family:var(--grid-font-family)}.viewport{height:100%;min-height:300px;overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface);scrollbar-gutter:stable}.viewport.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.groups-viewport{height:100%;min-height:300px}.groups-scroll-container{max-height:var(--grid-height, 600px);overflow-y:auto;overflow-x:hidden}.table-viewport{background-color:var(--grid-surface);height:var(--table-height, auto);min-height:var(--table-min-height, 100px);overflow-x:auto;overflow-y:auto}.pivot-viewport{min-height:var(--table-min-height, 300px);overflow-x:auto;overflow-y:auto;background-color:var(--grid-surface)}.pivot-viewport .cdk-virtual-scroll-content-wrapper{width:auto;height:auto}.table-wrapper{min-width:100%;overflow-x:visible}.incremental-row-container .eru-grid-table,.eru-grid-table{width:100%!important;border-collapse:separate;border-spacing:0;table-layout:fixed!important;background-color:var(--grid-surface);color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);line-height:var(--grid-line-height-body)}.eru-grid-table th,.eru-grid-table td{text-align:left;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;color:var(--grid-on-surface);min-width:0;max-width:100%!important;box-sizing:border-box;position:relative}.eru-grid-table th{background-color:var(--grid-header-bg, var(--grid-surface-container))}thead.eru-wrap-headers th{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;height:auto}thead.eru-wrap-headers th .column-label,thead.eru-wrap-headers th .header-label{white-space:normal!important;overflow:visible!important;text-overflow:clip!important;word-break:break-word;overflow-wrap:anywhere}.eru-grid-table tbody td{background-color:transparent}.eru-grid-table thead{background-color:var(--grid-header-bg, var(--grid-surface-container));transform:translateZ(0);will-change:transform;backface-visibility:hidden}.eru-grid-table thead.freeze-header-enabled{position:sticky!important;top:0!important;z-index:100!important}.eru-grid-table thead th{background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface));font-family:var(--grid-font-family);font-weight:var(--grid-header-font-weight);font-size:var(--grid-header-font-size)}.checkbox-column{width:50px;min-width:50px;max-width:50px;text-align:center;background-color:var(--grid-surface-container)}.checkbox-column input[type=checkbox]{width:16px;height:16px;cursor:pointer;accent-color:var(--grid-primary);border-radius:var(--grid-border-radius)}.checkbox-column input[type=checkbox]:focus{outline:2px solid var(--grid-primary);outline-offset:2px}.action-column{text-align:center;background-color:var(--grid-surface-container)}.action-column mat-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);cursor:pointer}.action-column mat-icon:hover{color:var(--grid-primary)}.action-column .action-icons{display:flex;align-items:center;justify-content:center;gap:6px;overflow-x:auto;scrollbar-width:none}.action-column .action-icons::-webkit-scrollbar{display:none}.action-column .action-icon{flex:0 0 auto}.eru-grid-action-menu .mat-mdc-menu-item mat-icon{margin-right:8px;font-size:18px;width:18px;height:18px;line-height:18px;color:var(--grid-on-surface-variant)}.group-header{background-color:var(--grid-surface-container);color:var(--grid-on-surface);font-size:var(--grid-font-size-caption);font-weight:500;border-bottom:1px solid var(--grid-outline);cursor:pointer;transition:background-color .2s ease}.group-header:hover{background-color:var(--grid-surface-container-high)}.group-header .group-title{font-weight:600;color:var(--grid-primary)}.group-header .group-row-count{color:var(--grid-on-surface-variant);font-size:var(--grid-font-size-caption);margin-left:var(--grid-spacing-sm)}.row-item{background-color:var(--grid-surface);transition:background-color .15s ease}.row-item:nth-child(odd){background-color:var(--grid-zebra-odd, var(--grid-surface))}.row-item:nth-child(2n){background-color:var(--grid-zebra-even, var(--grid-surface))}.row-item:hover{background-color:var(--grid-row-hover)}.required-toggle-row{background-color:var(--grid-surface-container, #f3edf7);border-bottom:1px solid var(--grid-outline-variant, #cac4d0)}.required-toggle-row .required-toggle-cell{padding:4px 8px!important;text-align:center;vertical-align:middle;position:relative}.required-toggle-row .required-toggle-cell .required-label{position:absolute;top:2px;left:4px;font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:400;text-transform:lowercase}.required-toggle-row .required-toggle-cell mat-checkbox{display:flex;justify-content:center;align-items:center}.table-column-header{padding:0 var(--grid-header-padding-x);height:var(--grid-header-row-height, auto)}.column-header{font-weight:var(--grid-header-font-weight);text-transform:var(--grid-header-text-transform);letter-spacing:var(--grid-header-letter-spacing);text-align:center!important;font-size:var(--grid-header-font-size);position:relative;-webkit-user-select:none;user-select:none;background-color:var(--grid-header-bg, var(--grid-surface-container));color:var(--grid-header-color, var(--grid-on-surface))}.column-header:hover{background-color:var(--grid-header-hover-bg, var(--grid-surface-container-high))}.column-drag-handle{position:absolute;left:0;top:0;bottom:0;width:12px;cursor:grab;opacity:0;transition:opacity .2s ease,background-color .2s ease;z-index:2;display:flex;align-items:center;justify-content:center;border-right:1px solid transparent}.column-drag-handle:after{content:\"\\22ee\\22ee\";font-size:14px;color:var(--grid-on-surface-variant);transform:rotate(90deg)}.column-drag-handle:hover{background-color:var(--grid-surface-container-high);border-right-color:var(--grid-outline)}.column-header:hover .column-drag-handle{opacity:1}.column-drag-handle:active{cursor:grabbing}.sortable-header{cursor:pointer}.sortable-header .column-label{flex:1}.sortable-header .sort-indicator{display:inline-flex;align-items:center;gap:2px;margin-left:4px;cursor:pointer;vertical-align:middle;opacity:0;transition:opacity .15s ease}.sortable-header .sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.sortable-header .sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.sortable-header .sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.sortable-header .sort-indicator .sort-tri-active{opacity:1}.sortable-header .sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.sortable-header .sort-indicator .sort-priority{font-size:9px;font-weight:600;color:var(--grid-primary, #6750a4);line-height:1;min-width:12px;text-align:center}.sortable-header:hover .sort-indicator,.sortable-header.sort-asc .sort-indicator,.sortable-header.sort-desc .sort-indicator{opacity:1}.sortable-header:hover .sort-indicator .sort-tri:not(.sort-tri-active){opacity:.6}.sort-asc,.sort-desc{background-color:var(--grid-surface-container-low, rgba(103, 80, 164, .04))}.dragging{opacity:1;background-color:var(--grid-surface-container);box-shadow:var(--grid-elevation-2)}.drag-over{background-color:var(--grid-surface-container);border-color:var(--grid-primary)}.data-cell{background-color:transparent;color:var(--grid-on-surface);font-family:var(--grid-font-family);font-size:var(--grid-font-size-body);font-feature-settings:var(--grid-font-feature-numeric);padding:0 var(--grid-cell-padding-x)}.cell-content{align-items:center}.cell-content .mdc-text-field{padding:0px var(--grid-spacing-xxs)!important}.cell-display-text{align-items:center;padding:0px var(--grid-spacing-xs)}.ghost-loading-row{background-color:transparent}.ghost-cell-container{padding:var(--grid-spacing-sm)}.ghost-cell{height:20px;width:100%;background-color:var(--grid-surface-container);animation:pulse 1.5s ease-in-out infinite;border-radius:var(--grid-border-radius)}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.resizing{cursor:col-resize;-webkit-user-select:none;user-select:none}.column-resizer{position:absolute;right:0;top:0;bottom:0;width:4px;cursor:col-resize;background-color:transparent;transition:background-color .2s ease}.column-resizer:hover{background-color:var(--grid-primary)}.group-separator{height:var(--grid-spacing-sm);background-color:var(--grid-surface-variant)}.group-separator .separator-cell{background-color:var(--grid-surface-variant);border:none;height:var(--grid-spacing-sm)}.error-state{background-color:var(--grid-error-container);color:var(--grid-error);border-color:var(--grid-error)}.error-message{background-color:var(--grid-error);color:#fff;padding:var(--grid-spacing-sm);border-radius:var(--grid-border-radius);font-size:var(--grid-font-size-caption)}.incremental-row-container .eru-grid-table tbody,.incremental-row-container .eru-grid-table{position:relative}.incremental-row-container .eru-grid-table.show-column-lines{border-right:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important;border-top:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table.show-column-lines:not(.freeze-header){border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table:not(.show-column-lines){border:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.incremental-row-container .eru-grid-table thead:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:calc(var(--grid-divider-width, 1px) * 2);background-color:var(--grid-divider-color, var(--grid-outline, #e0e0e0));pointer-events:none;z-index:10}.incremental-row-container .eru-grid-table.show-column-lines thead th,.incremental-row-container .eru-grid-table.show-column-lines tbody td{border-left:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}.incremental-row-container .eru-grid-table.show-row-lines thead th,.incremental-row-container .eru-grid-table.show-row-lines tbody td{border-bottom:var(--grid-divider-width, 1px) solid var(--grid-divider-color, var(--grid-outline, #e0e0e0))!important}@media(max-width:768px){.incremental-row-container{height:600px}.eru-grid-table th,.eru-grid-table td{font-size:var(--grid-font-size-caption)}.checkbox-column{width:40px;min-width:40px;max-width:40px}}@media(prefers-contrast:high){.eru-grid-table th,.eru-grid-table td{border-width:2px}.row-item:hover{border-width:2px;border-color:var(--grid-primary)}}@media(prefers-reduced-motion:reduce){.row-item,.column-drag-handle,.ghost-cell{transition:none;animation:none}}.pivot-table .nested-header{text-align:center;font-weight:600;background:var(--grid-surface-container)}.pivot-table .nested-header.row-dimension-header{background:var(--grid-surface-container);font-weight:600}.pivot-table .pivot-header-leafcols{padding:0;margin:0;height:0}.pivot-table .pivot-header-level.level-0 .nested-header{font-size:14px;padding:12px 8px}.pivot-table .pivot-header-level.level-1 .nested-header{font-size:13px;padding:10px 6px}.pivot-table .pivot-header-level.level-2 .nested-header{font-size:12px;padding:8px 4px}.pivot-table .nested-header:hover{background:var(--grid-surface-variant);color:var(--grid-primary);transition:all .2s ease}.pivot-table .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-table .pivot-cell-content{display:flex;justify-content:center;align-items:center;min-height:38px}.pivot-table .pivot-repeated-value .cell-content,.pivot-table .pivot-repeated-value .pivot-cell-content{visibility:hidden}.pivot-table .pivot-group-start.row-dimension-cell{border-top:1px solid var(--grid-outline, #79757f)}.pivot-mode .incremental-row-container{display:flex;flex-direction:column;height:auto;max-height:85vh;overflow:auto}.pivot-mode .h-shell{position:relative;width:calc(100% - var(--scrollbar-width, 17px))!important;top:0;z-index:1;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .h-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell{position:relative;bottom:50px;flex-shrink:0;overflow-x:hidden;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .gt-shell::-webkit-scrollbar{display:none}.pivot-mode .gt-shell table{border-bottom:var(--grid-outline-width, 1px) solid var(--grid-outline, #e0e0e0)!important}.pivot-mode .gt-shell.adjust-bottom-vs{bottom:66px!important}.pivot-mode .gt-shell.adjust-bottom:not(.adjust-bottom-vs){bottom:calc(66px - var(--scrollbar-width, 17px))!important}.pivot-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.pivot-mode .header-shell::-webkit-scrollbar{display:none}.pivot-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.pivot-mode .header-shell .eru-grid-table{margin-bottom:0;width:100%;table-layout:fixed}.pivot-mode .header-shell .eru-grid-table thead{background:var(--grid-surface-container)}.pivot-mode .header-shell .eru-grid-table thead th{background:var(--grid-surface-container);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .header-shell .eru-grid-table thead th.sticky-column{position:sticky;background:var(--grid-surface-container);z-index:111}.pivot-mode .header-shell .eru-grid-table tbody td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-container{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden}.pivot-mode .pivot-table{width:auto!important;min-width:100%!important;table-layout:fixed!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important}.pivot-mode .pivot-table td,.pivot-mode .pivot-table th{box-sizing:border-box!important;flex:none!important;flex-shrink:0!important;flex-grow:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-table{table-layout:fixed!important;width:100%!important}.pivot-mode .pivot-table *{max-width:var(--col-width)!important;box-sizing:border-box!important}.pivot-mode .pivot-table colgroup{width:100%!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex-basis:var(--col-width)!important;flex:0 0 var(--col-width)!important}.pivot-mode .pivot-table table{width:100%!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important}.pivot-mode .pivot-table[style*=--table-total-width]{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important}.pivot-mode .pivot-table colgroup col{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;flex:0 0 var(--col-width)!important;flex-basis:var(--col-width)!important;flex-grow:0!important;flex-shrink:0!important;overflow:hidden!important}.pivot-mode .pivot-table tbody td,.pivot-mode .pivot-table thead th{width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.pivot-mode .pivot-table .cell-content,.pivot-mode .pivot-table data-cell{width:100%!important;max-width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important;display:block!important}.pivot-mode .pivot-table table{width:var(--table-total-width)!important;min-width:var(--table-total-width)!important;max-width:var(--table-total-width)!important;table-layout:fixed!important;border-collapse:collapse!important;border-spacing:0!important;word-wrap:break-word!important;word-break:break-all!important}.pivot-mode .pivot-tbody tr.pivot-row{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important}.pivot-mode .pivot-tbody tr.pivot-row:hover{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-tbody tr.pivot-row:nth-child(2n){background-color:#00000005}.pivot-mode .pivot-tbody tr.pivot-row td{min-height:var(--grid-data-row-height, 50px)!important;height:var(--grid-data-row-height, 50px)!important;vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content{min-height:calc(var(--grid-data-row-height, 50px) - 2px);display:flex;align-items:center;justify-content:center}.pivot-mode .pivot-tbody tr.pivot-row td .cell-content data-cell{width:100%;min-height:calc(var(--grid-data-row-height, 50px) - 4px);display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}.pivot-mode .pivot-cell{vertical-align:middle;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:var(--col-width)!important;min-width:var(--col-width)!important;max-width:var(--col-width)!important}.pivot-mode .pivot-cell.aggregated-value{font-weight:500;font-family:Roboto Mono,monospace}.pivot-mode .pivot-cell .cell-content{display:flex;justify-content:center;align-items:center;min-height:var(--grid-header-row-height, 40px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0}.pivot-mode .pivot-table .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.pivot-mode .pivot-table .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .subtotal-row td:first-child{color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row td.aggregated-value{font-weight:500;color:var(--grid-primary)}.pivot-mode .pivot-table .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.pivot-mode .pivot-table .subtotal-bold td{font-weight:600!important;font-style:normal!important}.pivot-mode .pivot-table .subtotal-bold td.aggregated-value{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td{font-style:italic!important}.pivot-mode .pivot-table .subtotal-italic td:first-child{font-weight:600!important}.pivot-mode .pivot-table .subtotal-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.pivot-mode .pivot-table .subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted td.aggregated-value{font-weight:500!important;color:var(--grid-primary)!important}.pivot-mode .pivot-table .subtotal-highlighted:hover,.pivot-mode .pivot-table .subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-row{background-color:var(--grid-surface-container-high)!important;font-weight:700;font-size:var(--grid-font-size-body)}.pivot-mode .pivot-table .grand-total-row td{background-color:var(--grid-surface-container-high)!important;color:var(--grid-on-surface)}.pivot-mode .pivot-table .grand-total-row td:first-child{font-style:normal;font-weight:800;color:var(--grid-primary)}.pivot-mode .pivot-table .grand-total-row td.aggregated-value{font-weight:500;color:var(--grid-primary);font-family:Roboto Mono,monospace}.pivot-mode .pivot-table .grand-total-row:hover,.pivot-mode .pivot-table .grand-total-row:hover td{background-color:var(--grid-surface-container-high)!important}.pivot-mode .pivot-table .grand-total-bold td{font-weight:700!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-bold td.aggregated-value{font-weight:700!important}.pivot-mode .pivot-table .grand-total-italic td,.pivot-mode .pivot-table .grand-total-italic td.aggregated-value{font-style:italic!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted{background-color:var(--grid-primary)!important;box-shadow:var(--grid-elevation-2)!important}.pivot-mode .pivot-table .grand-total-highlighted td{background-color:var(--grid-primary)!important;color:var(--grid-on-primary)!important;font-weight:500!important;font-style:normal!important}.pivot-mode .pivot-table .grand-total-highlighted td.aggregated-value{color:var(--grid-on-primary)!important;font-weight:500!important}.pivot-mode .pivot-table .grand-total-highlighted:hover,.pivot-mode .pivot-table .grand-total-highlighted:hover td{background-color:var(--grid-primary)!important}.pivot-mode .pivot-table .collapsible-header{position:relative}.pivot-mode .pivot-table .collapsible-header .header-content{display:flex;align-items:center;justify-content:space-between;gap:var(--grid-spacing-xs);padding:var(--grid-spacing-xs) var(--grid-spacing-sm)}.pivot-mode .pivot-table .collapsible-header .header-label{flex:1;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn{background:none;border:none;cursor:pointer;padding:var(--grid-spacing-xxs);margin:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--grid-border-radius);color:var(--grid-on-surface-variant);transition:all .2s ease;font-size:12px;font-weight:600}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:hover{background-color:var(--grid-surface-container);color:var(--grid-primary);transform:scale(1.1)}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn:focus{outline:2px solid var(--grid-primary);outline-offset:1px}.pivot-mode .pivot-table .collapsible-header .collapse-toggle-btn .collapse-icon{display:block;line-height:1;font-family:monospace;font-size:14px}.pivot-mode .pivot-table .collapsible-header.expanded .collapse-toggle-btn .collapse-icon{color:var(--grid-primary)}.pivot-mode .pivot-table .collapsible-header.collapsed{background-color:var(--grid-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .header-label{font-style:italic;color:var(--grid-on-surface-variant)}.pivot-mode .pivot-table .collapsible-header.collapsed .collapse-toggle-btn .collapse-icon{color:var(--grid-outline)}.pivot-mode .pivot-table .collapsible-header:hover{background-color:var(--grid-surface-container)}.pivot-mode .pivot-table .collapsible-header:hover .header-label{color:var(--grid-on-surface)}.pivot-mode .pivot-table .pivot-single-table{display:flex;flex-direction:column;height:100%;width:100%;overflow:hidden;min-height:var(--table-min-height)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container{flex-shrink:0;background:var(--grid-surface)!important;overflow-x:auto;overflow-y:hidden;min-height:100px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table{width:auto;min-width:100%;height:auto!important;min-height:100px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th{background:var(--grid-surface-container)!important;padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:40px!important;height:auto!important;position:relative;visibility:visible!important;color:var(--grid-on-surface)!important}.pivot-mode .pivot-table .pivot-single-table .pivot-header-container .pivot-table th.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:101!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container{flex:1;overflow:auto;min-height:300px!important;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-viewport{height:100%!important;width:100%!important;overflow-x:auto!important;overflow-y:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table{width:auto;min-width:100%;height:auto!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td{padding:8px 6px!important;white-space:nowrap;min-width:50px;min-height:32px!important;height:auto!important;background:var(--grid-surface)!important;color:var(--grid-on-surface)!important;visibility:visible!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table td.sticky-column,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table td.sticky-column{position:sticky!important;background:var(--grid-surface-container)!important;border-right:2px solid var(--grid-primary)!important;box-shadow:2px 0 4px #0000001a;z-index:100!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr{height:auto!important;min-height:50px!important}.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-table tbody tr.pivot-row,.pivot-mode .pivot-table .pivot-single-table .pivot-data-container .pivot-data-table tbody tr.pivot-row{visibility:visible!important;display:table-row!important}.pivot-mode .pivot-table .collapsed-column-group{background-color:var(--grid-surface-container);border-left:3px solid var(--grid-primary)}.pivot-mode .pivot-table .collapsed-column-group:hover{background-color:var(--grid-surface-container-high)}.pivot-row.subtotal-row{background-color:var(--grid-surface-variant);font-weight:500}.pivot-row.subtotal-row.subtotal-bold{font-weight:500}.pivot-row.subtotal-row.subtotal-italic{font-style:italic}.pivot-row.subtotal-row.subtotal-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.grand-total-row{background-color:var(--grid-surface-container);font-weight:600}.pivot-row.grand-total-row.grand-total-bold{font-weight:800}.pivot-row.grand-total-row.grand-total-italic{font-style:italic}.pivot-row.grand-total-row.grand-total-highlighted{background-color:var(--grid-primary);color:var(--grid-on-primary)}.pivot-row.first-visible-row{background-color:#6750a41a!important;position:relative}.pivot-row.first-visible-row:before{content:\"\\1f441\\fe0f First Visible\";position:absolute;top:-20px;left:0;background:var(--grid-primary);color:var(--grid-on-primary);padding:2px 6px;font-size:10px;border-radius:2px;z-index:1000}.header-wrap-text{white-space:pre-wrap;word-break:auto-phrase}.group-header-row{display:flex;align-items:center;justify-content:space-between;width:100%;padding-right:12px}.custom-collapse-header{background-color:var(--grid-surface-variant);padding:8px 20px;border-top-left-radius:12px;border-top-right-radius:12px;cursor:pointer;display:flex;width:fit-content;align-items:center;-webkit-user-select:none;user-select:none;min-width:200px;margin-bottom:10px;position:sticky;left:1px;z-index:116}.custom-collapse-header .collapse-arrow{display:inline-block;margin-right:8px;font-size:12px;color:var(--grid-on-surface-variant);transition:transform .2s ease;transform:rotate(0)}.custom-collapse-header .collapse-arrow.rotate-arrow{transform:rotate(270deg)}.custom-collapse-header .f-12{font-size:12px;color:var(--grid-on-surface)}.custom-collapse-header .group-sort-indicator{display:inline-flex;align-items:center;margin-left:8px}.custom-collapse-header .group-sort-indicator .sort-triangles{display:flex;flex-direction:column;align-items:center;gap:2px}.custom-collapse-header .group-sort-indicator .sort-tri{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;cursor:pointer;transition:border-color .15s ease}.custom-collapse-header .group-sort-indicator .sort-tri-up{border-bottom:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-down{border-top:5px solid var(--grid-on-surface-variant, #49454f);opacity:.3}.custom-collapse-header .group-sort-indicator .sort-tri-active{opacity:1}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-up{border-bottom-color:var(--grid-primary, #6750a4)}.custom-collapse-header .group-sort-indicator .sort-tri-active.sort-tri-down{border-top-color:var(--grid-primary, #6750a4)}.excel-download-icon{cursor:pointer}.excel-download-icon:hover{opacity:.75}.excel-download-bar{display:flex;justify-content:flex-end;padding:4px 12px}.table-mode .header-shell{flex-shrink:0;width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .header-shell::-webkit-scrollbar{display:none}.table-mode .header-shell.apply-cdk-width{width:calc(var(--table-total-width) + 10px)!important}.table-mode .subtotal-row{background-color:var(--grid-surface-container)!important;font-weight:600}.table-mode .subtotal-row td{background-color:var(--grid-surface-container);color:var(--grid-on-surface-variant)}.table-mode .subtotal-row td:first-child{color:var(--grid-primary)}.table-mode .subtotal-row td.subtotal-cell{font-weight:500}.table-mode .subtotal-row td.subtotal-cell .subtotal-label{font-weight:600;color:var(--grid-primary)}.table-mode .subtotal-row:hover{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row:hover td{background-color:var(--grid-surface-container-high)}.table-mode .subtotal-row.subtotal-bold td{font-weight:600!important;font-style:normal!important}.table-mode .subtotal-row.subtotal-italic td{font-style:italic!important}.table-mode .subtotal-row.subtotal-italic td:first-child{font-weight:600!important}.table-mode .subtotal-row.subtotal-highlighted{background-color:var(--grid-surface-variant)!important}.table-mode .subtotal-row.subtotal-highlighted td{background-color:var(--grid-surface-variant)!important;font-weight:700!important;font-style:normal!important;color:var(--grid-primary)!important}.table-mode .subtotal-row.subtotal-highlighted:hover,.table-mode .subtotal-row.subtotal-highlighted:hover td{background-color:var(--grid-surface-container-high)!important}.table-mode .subtotal-row-shell{width:100%;box-sizing:border-box;padding-right:var(--scrollbar-width, 17px);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.table-mode .subtotal-row-shell::-webkit-scrollbar{display:none}.board-mode-host{overflow:hidden;display:flex;flex-direction:column;max-height:var(--grid-height, 600px)}.board-mode-host .board-view-container{display:flex;flex-direction:column;flex:1;min-height:0}.board-mode-host .board-sort-bar{display:flex;align-items:center;gap:6px;padding:8px 16px;flex-shrink:0;border-bottom:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);overflow-x:auto}.board-mode-host .board-sort-bar .board-sort-label{font-size:12px;font-weight:500;color:var(--grid-on-surface-variant, #49454f);white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-outline-variant, #cac4d0);background:var(--grid-surface, #fffbfe);color:var(--grid-on-surface, #1d1b20);font-size:12px;white-space:nowrap}.board-mode-host .board-sort-bar .board-sort-chip-active{background:var(--grid-surface-container);border-color:var(--grid-outline, #79757f);color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-sort-bar .board-sort-chip-label{pointer-events:none}.board-mode-host .board-sort-bar .board-sort-chip-arrow{font-size:10px;line-height:1;cursor:pointer;padding:2px;border-radius:4px}.board-mode-host .board-sort-bar .board-sort-chip-arrow:hover{background:#00000014}.board-mode-host .board-sort-bar .board-sort-chip-priority{font-size:9px;font-weight:700;background:var(--grid-primary, #6750a4);color:var(--grid-on-primary, #ffffff);border-radius:50%;width:14px;height:14px;display:inline-flex;align-items:center;justify-content:center}.board-mode-host .board-sort-bar .board-sort-chip-remove{font-size:10px;cursor:pointer;padding:2px;border-radius:4px;color:var(--grid-on-surface-variant, #49454f)}.board-mode-host .board-sort-bar .board-sort-chip-remove:hover{background:#00000014;color:var(--grid-error, #b3261e)}.board-mode-host .board-sort-bar .board-sort-add-btn{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:16px;border:1px dashed var(--grid-outline-variant, #cac4d0);background:transparent;color:var(--grid-on-surface-variant, #49454f);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease,border-color .15s ease}.board-mode-host .board-sort-bar .board-sort-add-btn .board-sort-add-icon{font-size:14px;width:14px;height:14px}.board-mode-host .board-sort-bar .board-sort-add-btn:hover{background:var(--grid-surface-container-low, #f7f2fa);border-color:var(--grid-primary, #6750a4);color:var(--grid-primary, #6750a4)}.board-mode-host .board-sort-bar .board-sort-clear{display:inline-flex;align-items:center;padding:4px 10px;border-radius:16px;border:1px solid var(--grid-error, #b3261e);background:transparent;color:var(--grid-error, #b3261e);font-size:12px;cursor:pointer;white-space:nowrap;transition:background .15s ease}.board-mode-host .board-sort-bar .board-sort-clear:hover{background:#b3261e14}.board-mode-host .board-columns-wrapper{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr)));grid-auto-rows:auto;align-items:start;gap:16px;flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;align-content:start;justify-content:start}.board-mode-host .board-columns-wrapper.board-columns-nowrap{grid-auto-flow:column;grid-template-columns:none;grid-template-rows:auto;grid-auto-rows:auto;grid-auto-columns:minmax(var(--board-col-min-width, 300px),var(--board-col-max-width, 1fr));overflow-x:auto;overflow-y:hidden}.board-mode-host .board-column{max-height:var(--board-column-height, 420px);min-width:0;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column.board-column-accented{border-top:3px solid var(--board-group-color, transparent)}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 14px;font-weight:600;flex-shrink:0;background-color:transparent}.board-mode-host .board-column .column-header:hover{background-color:transparent}.board-mode-host .board-column .column-header .column-header-title{font-size:15px;font-weight:700;letter-spacing:.2px;line-height:1.2;color:var(--grid-on-surface, #1d1b20);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.board-mode-host .board-column .column-header .column-header-title-cell{display:inline-flex;align-items:center;flex:1 1 auto;min-width:0;overflow:visible;text-overflow:clip}.board-mode-host .board-column .column-header .column-header-title-cell data-cell,.board-mode-host .board-column .column-header .column-header-title-cell .data-cell-component,.board-mode-host .board-column .column-header .column-header-title-cell .container{padding:0!important;margin:0!important;border:none!important;background:transparent!important;min-height:0!important;height:auto!important;width:auto!important;max-width:100%!important;overflow:visible!important}.board-mode-host .board-column .column-header .column-header-title-cell .status-display,.board-mode-host .board-column .column-header .column-header-title-cell .status-display-content,.board-mode-host .board-column .column-header .column-header-title-cell .status-text,.board-mode-host .board-column .column-header .column-header-title-cell .tag-display,.board-mode-host .board-column .column-header .column-header-title-cell .tag-text{max-width:none!important;overflow:visible!important;text-overflow:clip!important}.board-mode-host .board-column .column-header .column-header-count{font-size:10px;font-weight:600;color:var(--eru-board-count-color, var(--grid-on-surface-variant, #49454f));background:var(--eru-board-count-bg, var(--grid-surface-variant, #e7e0ec));border-radius:10px;padding:3px 10px;white-space:nowrap;flex-shrink:0}.board-mode-host .board-column-body{flex:0 1 auto;min-height:0}.board-mode-host .board-card-container{box-sizing:border-box;overflow:hidden;border-radius:8px;transition:background-color .15s ease,box-shadow .15s ease}.board-mode-host .board-card-container.show-row-lines{box-shadow:inset 0 0 0 var(--grid-divider-width, 1px) var(--grid-divider-color, var(--grid-outline, #e0e0e0))}.board-mode-host .board-card-container:hover{background-color:var(--eru-board-card-hover-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 8%, transparent))}.board-mode-host .board-card-container.selected{background-color:var(--eru-board-card-selected-bg, color-mix(in srgb, var(--mat-sys-primary, #1976d2) 14%, transparent));box-shadow:inset 0 0 0 2px var(--eru-board-card-selected-outline, var(--mat-sys-primary, #1976d2))}.board-mode-host .board-card{height:calc(100% - 8px);overflow:hidden;cursor:pointer}.board-mode-host .board-card mat-card-title{font-size:13px}.board-mode-host .board-card mat-card-subtitle{font-size:12px}.board-mode-host .board-card-field{display:flex;flex-direction:column;margin-bottom:4px}.board-mode-host .board-field-label{font-size:10px;color:var(--grid-on-surface-variant, #49454f);font-weight:500;text-transform:uppercase;letter-spacing:.5px}.board-mode-host .board-ghost-card{margin:8px;padding:16px;background:var(--grid-surface, #fef7ff);border-radius:8px;animation:board-pulse 1.5s ease-in-out infinite}.board-mode-host .board-ghost-line{height:12px;background:var(--grid-surface-variant, #e7e0ec);border-radius:4px;margin-bottom:8px}.board-mode-host .board-ghost-line--short{width:60%}@keyframes board-pulse{0%,to{opacity:1}50%{opacity:.5}}th.row-expand-toggle,td.row-expand-toggle{width:40px!important;min-width:40px!important;max-width:40px!important;padding:0!important;text-align:center;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;box-sizing:border-box}.row-expand-icon{font-size:20px;width:20px;height:20px;line-height:20px;color:var(--grid-on-surface-variant);transition:transform .15s ease-in-out}.row-expand-icon.expanded{transform:rotate(90deg)}.row-detail{background:var(--grid-surface-container)}.row-detail .row-detail-cell{padding:var(--grid-spacing-sm) var(--grid-spacing-md);border-bottom:1px solid var(--grid-outline-variant)}.row-detail .row-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:var(--grid-spacing-sm) var(--grid-spacing-md)}.row-detail .row-detail-field{display:flex;flex-direction:column;gap:var(--grid-spacing-xxs);min-width:0}.row-detail .row-detail-label{font-size:var(--grid-font-size-caption);color:var(--grid-on-surface-variant);font-weight:500}.row-detail .row-detail-value{min-width:0}.row-detail .row-detail-value data-cell{display:block;width:100%}\n"] }]
14645
14697
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { allViewports: [{
14646
14698
  type: ViewChildren,
14647
14699
  args: [CdkVirtualScrollViewport]
@@ -14781,5 +14833,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
14781
14833
  * Generated bundle index. Do not edit.
14782
14834
  */
14783
14835
 
14784
- export { AttachmentComponent, CheckboxComponent, ColumnConstraintsService, CurrencyComponent, CustomVirtualScrollStrategy, DATA_TYPES, DATETIME_FORMATS, DATE_FORMATS, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, INHERITED_FIELD_KEYS, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, MONTH_SHORT_NAMES, NumberComponent, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent, evaluateRowCondition, formatDateWithPattern, matchColorRange, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseDateWithPattern, resolveRowValue, statusPillColors };
14836
+ export { AttachmentComponent, CheckboxComponent, ColumnConstraintsService, CurrencyComponent, CustomVirtualScrollStrategy, DATA_TYPES, DATETIME_FORMATS, DATE_FORMATS, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, INHERITED_FIELD_KEYS, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, MONTH_SHORT_NAMES, NumberComponent, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent, evaluateRowCondition, formatDateWithPattern, matchColorRange, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseDateWithPattern, resolveRowValue, statusPillColors, tagPillColors };
14785
14837
  //# sourceMappingURL=eru-grid.mjs.map