eru-grid 0.0.29 → 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, signal, computed, DOCUMENT, effect, InjectionToken, ElementRef, input, EventEmitter, Output, ViewEncapsulation, ChangeDetectionStrategy, Component, ViewChild, Directive, ChangeDetectorRef, model, Renderer2, Input, HostListener, NgZone, ViewChildren } from '@angular/core';
2
+ import { Injectable, inject, signal, computed, DOCUMENT, effect, InjectionToken, ElementRef, input, EventEmitter, Output, ViewEncapsulation, ChangeDetectionStrategy, Component, ViewChild, Directive, untracked, ChangeDetectorRef, model, Renderer2, Input, HostListener, NgZone, ViewChildren } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import * as i2 from '@angular/material/form-field';
@@ -34,9 +34,9 @@ import { MatChipsModule } from '@angular/material/chips';
34
34
  import { FixedSizeVirtualScrollStrategy, ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
35
35
  import { BreakpointObserver } from '@angular/cdk/layout';
36
36
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
37
- import * as i6 from '@angular/material/card';
37
+ import * as i5 from '@angular/material/card';
38
38
  import { MatCardModule } from '@angular/material/card';
39
- import * as i8 from '@angular/material/menu';
39
+ import * as i7 from '@angular/material/menu';
40
40
  import { MatMenuModule } from '@angular/material/menu';
41
41
 
42
42
  class GridConfigService {
@@ -2549,6 +2549,13 @@ class EruGridStore {
2549
2549
  _dataRequest = signal(null, ...(ngDevMode ? [{ debugName: "_dataRequest" }] : []));
2550
2550
  // Request queue to handle multiple simultaneous requests
2551
2551
  _requestQueue = signal([], ...(ngDevMode ? [{ debugName: "_requestQueue" }] : []));
2552
+ // Column currently selected for editing in the design panel (by name)
2553
+ _selectedDesignColumn = signal(null, ...(ngDevMode ? [{ debugName: "_selectedDesignColumn" }] : []));
2554
+ selectedDesignColumn = this._selectedDesignColumn.asReadonly();
2555
+ // Emits the full columns array whenever the design panel edits column metadata.
2556
+ // Consumers (e.g. eru-studio) listen to persist the design back into their config.
2557
+ _columnDesignUpdate = signal(null, ...(ngDevMode ? [{ debugName: "_columnDesignUpdate" }] : []));
2558
+ columnDesignUpdate = this._columnDesignUpdate.asReadonly();
2552
2559
  // Computed signals
2553
2560
  columns = this._columns.asReadonly();
2554
2561
  groups = this._groups.asReadonly();
@@ -2786,8 +2793,15 @@ class EruGridStore {
2786
2793
  });
2787
2794
  }
2788
2795
  updateColumnRequired(columnName, required) {
2789
- const columns = this.columns().map(col => col.name === columnName ? { ...col, required } : col);
2796
+ this.updateColumnMeta(columnName, { required });
2797
+ }
2798
+ updateColumnMeta(columnName, patch) {
2799
+ const columns = this.columns().map(col => col.name === columnName ? { ...col, ...patch } : col);
2790
2800
  this.setColumns(columns);
2801
+ this._columnDesignUpdate.set(this.columns());
2802
+ }
2803
+ selectDesignColumn(columnName) {
2804
+ this._selectedDesignColumn.set(columnName);
2791
2805
  }
2792
2806
  updateColumnWidth(columnName, field_size) {
2793
2807
  const columns = this.columns().map(col => col.name === columnName ? { ...col, field_size: field_size } : col);
@@ -3391,8 +3405,16 @@ class EruGridStore {
3391
3405
  * Set the dynamic data request
3392
3406
  */
3393
3407
  setDynamicDataRequest(request) {
3408
+ // Normalize the string overload (used by simpler cell types) into a descriptor.
3409
+ const descriptor = typeof request === 'string' ? { key: request } : request;
3410
+ if (!descriptor.key) {
3411
+ return;
3412
+ }
3394
3413
  const currentRequests = this._dynamicDataRequest() || [];
3395
- this._dynamicDataRequest.set([...currentRequests, request]);
3414
+ // Replace any pending request for the same key so a changed search term
3415
+ // (field_str) supersedes the previous one instead of queuing duplicates.
3416
+ const deduped = currentRequests.filter(r => r.key !== descriptor.key);
3417
+ this._dynamicDataRequest.set([...deduped, descriptor]);
3396
3418
  }
3397
3419
  /**
3398
3420
  * Get the dynamic data request
@@ -3400,11 +3422,17 @@ class EruGridStore {
3400
3422
  getDynamicDataRequest() {
3401
3423
  return this._dynamicDataRequest();
3402
3424
  }
3425
+ /**
3426
+ * True if a request for the given key is already pending.
3427
+ */
3428
+ hasDynamicDataRequest(key) {
3429
+ return (this._dynamicDataRequest() || []).some(r => r.key === key);
3430
+ }
3403
3431
  removeDynamicDataRequest(key) {
3404
3432
  if (!this._dynamicDataRequest()) {
3405
3433
  return;
3406
3434
  }
3407
- this._dynamicDataRequest.set(this._dynamicDataRequest()?.filter((k) => k !== key) || []);
3435
+ this._dynamicDataRequest.set(this._dynamicDataRequest()?.filter(r => r.key !== key) || []);
3408
3436
  }
3409
3437
  /**
3410
3438
  * Set the dynamic data
@@ -6626,21 +6654,33 @@ class SelectComponent {
6626
6654
  const apiData = dynamicDataMap.get(apiName);
6627
6655
  if (apiData) {
6628
6656
  // Process API response data
6629
- // Expected format: array of { name, label } or array of strings
6657
+ // Expected format: array of { [apiField]: value } objects, or strings.
6630
6658
  let processedOptions = [];
6631
6659
  if (Array.isArray(apiData)) {
6632
- processedOptions = apiData.map((item) => {
6633
- if (typeof item === 'string') {
6634
- return { value: item, label: item };
6660
+ processedOptions = apiData
6661
+ .map((item) => {
6662
+ if (item === null || item === undefined) {
6663
+ return null;
6635
6664
  }
6636
- else if (item && typeof item === 'object') {
6637
- return {
6638
- value: item[apiField || ''],
6639
- label: item[apiField || '']
6640
- };
6665
+ if (typeof item !== 'object') {
6666
+ // Primitive (string/number) — use it directly.
6667
+ return { value: item, label: String(item) };
6641
6668
  }
6642
- return { value: item[apiField || ''], label: String(item[apiField || '']) };
6643
- });
6669
+ // Read the configured field. The value may be nested inside
6670
+ // the record (e.g. ENTITY_DATA rows), so search the object
6671
+ // tree for the field key rather than only the top level.
6672
+ let raw = apiField ? this.findFieldValue(item, apiField) : undefined;
6673
+ if (raw === undefined || raw === null) {
6674
+ // Fall back to the first primitive property so options
6675
+ // still render if the field name doesn't match.
6676
+ raw = this.firstPrimitiveValue(item);
6677
+ }
6678
+ if (raw === undefined || raw === null) {
6679
+ return null;
6680
+ }
6681
+ return { value: raw, label: String(raw) };
6682
+ })
6683
+ .filter((o) => o !== null);
6644
6684
  }
6645
6685
  // Apply search filter if searchText is provided
6646
6686
  if (!searchText) {
@@ -6690,21 +6730,47 @@ class SelectComponent {
6690
6730
  }
6691
6731
  }
6692
6732
  });
6693
- // Effect to request API data when needed (separate from computed to avoid signal write errors)
6733
+ // Effect to request dynamic option data (API / ENTITY_DATA) from the consumer.
6734
+ // Lazy: only fires once the cell is activated for editing (the user wants to
6735
+ // see the options), not on grid load. Fetched ONCE PER COLUMN — the result is
6736
+ // cached in the store keyed by column, so every other row reuses it and we
6737
+ // skip the request when data is already present or a request is in flight.
6694
6738
  effect(() => {
6739
+ const active = this.isActive();
6695
6740
  const cfg = this.config();
6696
6741
  const store = this.eruGridStore();
6697
- if (cfg && ((cfg.option_type === 'API' && cfg.api_name) || (cfg.option_type === 'ENTITY_DATA' && cfg.entity_name)) && store) {
6698
- let apiName = cfg.api_name || '';
6699
- if (cfg.option_type === 'ENTITY_DATA') {
6700
- apiName = cfg.entity_name || '';
6701
- }
6702
- const currentRequests = store.getDynamicDataRequest() || [];
6703
- // Request data if not already requested
6704
- if (!currentRequests.includes(apiName)) {
6705
- store.setDynamicDataRequest(apiName);
6706
- }
6742
+ // Read the cache reactively so this re-evaluates once the column's data
6743
+ // arrives (and then short-circuits for every subsequent cell).
6744
+ const cache = store?.dynamicData();
6745
+ // Don't fetch until the user opens the dropdown for editing.
6746
+ if (!active) {
6747
+ return;
6748
+ }
6749
+ if (!cfg || !store) {
6750
+ return;
6751
+ }
6752
+ if (cfg.option_type !== 'API' && cfg.option_type !== 'ENTITY_DATA') {
6753
+ return;
6754
+ }
6755
+ // The map key the response is stored under: entity_name for ENTITY_DATA,
6756
+ // api_name for API (mirrors the lookup in filteredOptions()).
6757
+ const key = cfg.option_type === 'ENTITY_DATA' ? (cfg.entity_name || '') : (cfg.api_name || '');
6758
+ if (!key) {
6759
+ return;
6707
6760
  }
6761
+ // Already fetched for this column, or a fetch is already pending → reuse it.
6762
+ if ((cache && cache.has(key)) || store.hasDynamicDataRequest(key)) {
6763
+ return;
6764
+ }
6765
+ store.setDynamicDataRequest({
6766
+ key,
6767
+ optionType: cfg.option_type,
6768
+ entityName: cfg.entity_name,
6769
+ fieldName: cfg.field_name,
6770
+ apiName: cfg.api_name,
6771
+ apiField: cfg.api_field,
6772
+ search: untracked(() => this.searchText()) || ''
6773
+ });
6708
6774
  });
6709
6775
  }
6710
6776
  ngOnInit() {
@@ -6882,6 +6948,48 @@ class SelectComponent {
6882
6948
  trackByValueAndIndex(index, option) {
6883
6949
  return `${option?.value || ''}_${index}`;
6884
6950
  }
6951
+ /**
6952
+ * Find the value of `field` anywhere within `obj` (top-down, first match).
6953
+ * Returns only primitive values so nested wrapper objects are skipped — the
6954
+ * option value/label must be a scalar, not an object.
6955
+ */
6956
+ findFieldValue(obj, field) {
6957
+ if (!obj || typeof obj !== 'object') {
6958
+ return undefined;
6959
+ }
6960
+ if (Object.prototype.hasOwnProperty.call(obj, field)) {
6961
+ const direct = obj[field];
6962
+ if (direct === null || typeof direct !== 'object') {
6963
+ return direct;
6964
+ }
6965
+ }
6966
+ for (const key of Object.keys(obj)) {
6967
+ const child = obj[key];
6968
+ if (child && typeof child === 'object') {
6969
+ const found = this.findFieldValue(child, field);
6970
+ if (found !== undefined && found !== null) {
6971
+ return found;
6972
+ }
6973
+ }
6974
+ }
6975
+ return undefined;
6976
+ }
6977
+ /**
6978
+ * First primitive (non-object) property value found in the object tree.
6979
+ * Used as a last resort when the configured field cannot be located.
6980
+ */
6981
+ firstPrimitiveValue(obj) {
6982
+ if (obj === null || typeof obj !== 'object') {
6983
+ return obj;
6984
+ }
6985
+ for (const key of Object.keys(obj)) {
6986
+ const child = obj[key];
6987
+ if (child !== null && typeof child !== 'object') {
6988
+ return child;
6989
+ }
6990
+ }
6991
+ return undefined;
6992
+ }
6885
6993
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6886
6994
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: SelectComponent, isStandalone: true, selector: "eru-select", 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 }, multiple: { classPropertyName: "multiple", publicName: "multiple", 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" }, viewQueries: [{ propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true }], ngImport: i0, template: "@if(isActive()) {\n<mat-form-field [appearance]=\"getProperty('appearance') || 'outline'\" class=\"select-form-field\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"select-container\">\n <mat-select [placeholder]=\"getProperty('placeholder') || ''\" [multiple]=\"multiple()\"\n [disabled]=\"getProperty('disabled') || !isEditable()\" [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\" [compareWith]=\"compareWith\" panelClass=\"select-panel\" class=\"select-input\"\n (selectionChange)=\"onValueChange($event.value)\" (blur)=\"onBlur($event)\" (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n\n <mat-option disabled class=\"search-option\" (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-form-field [appearance]=\"getProperty('appearance') || 'outline'\" class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input matInput type=\"text\" class=\"search-input\" [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\" (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n @if (multiple()) {\n <div class=\"select-all-container\" (click)=\"$event.stopPropagation()\">\n <mat-checkbox [checked]=\"isAllSelected()\" [indeterminate]=\"isIndeterminate()\"\n (change)=\"toggleSelectAll($event.checked)\" (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <span class=\"select-all-text\">Select All</span>\n </mat-checkbox>\n </div>\n }\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n @if (multiple()) {\n <mat-option [value]=\"option.value\" (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n {{ option.label }}\n </mat-option>\n } @else {\n <mat-option [value]=\"option.value\">\n {{ option.label }}\n </mat-option>\n }\n }\n </mat-select>\n </div>\n</mat-form-field>\n} @else {\n<div class=\"select-display\" [class.select-display-editable]=\"isEditable()\" (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"select-drillable\" (click)=\"onDrillableClick($event)\">\n {{formatDisplayValue() || (getProperty('placeholder') || '')}}\n </span>\n } @else {\n {{formatDisplayValue() || (getProperty('placeholder') || '')}}\n }\n</div>\n}", styles: ["@charset \"UTF-8\";.select-form-field{width:100%}.select-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.select-container{width:100%}.select-display{width:100%;padding:8px 12px;min-height:30px;display:flex;align-items:center;cursor:default}.select-display.select-display-editable{cursor:pointer}.select-display.select-display-editable:hover{background-color:#0000000a}.select-drillable{color:#1976d2;cursor:pointer;text-decoration:underline}.select-drillable:hover{color:#1565c0}.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-pseudo-checkbox{display:none!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;align-items:stretch!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 4px 12px!important;display:flex!important;align-items:center!important;pointer-events:auto!important}.search-option .select-all-container .select-all-text{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 mat-checkbox .mdc-checkbox{display:none!important}.search-option .select-all-container mat-checkbox .mdc-form-field{padding:0!important;margin:0!important}.search-option .select-all-container mat-checkbox .mdc-label{padding:0 0 0 12px!important;margin:0!important;cursor:pointer!important}.search-option .select-all-container mat-checkbox.mat-mdc-checkbox-checked .mdc-label:before,.search-option .select-all-container mat-checkbox.mat-mdc-checkbox-indeterminate .mdc-label:before{content:\"\\2713\";font-size:16px;font-weight:700;color:var(--grid-on-surface, #1d1b20);margin-right:4px}.select-panel{min-width:200px!important}.select-input{padding-left:4px}.select-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.select-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.select-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.select-panel mat-option mat-pseudo-checkbox{display:none!important}.select-panel mat-option.mdc-list-item--selected:not(.search-option) .mdc-list-item__primary-text:before{content:\"\\2713\"!important;font-size:16px;font-weight:700;color:var(--grid-on-surface, #1d1b20);margin-right:8px;display:inline!important}mat-option .mdc-list-item__primary-text{line-height:1.5!important;white-space:normal!important}\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$2.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$2.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: MatCheckboxModule }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
6887
6995
  }
@@ -6968,20 +7076,40 @@ class StatusComponent {
6968
7076
  const value = this.value();
6969
7077
  this.currentValue.set(value);
6970
7078
  });
6971
- // Effect to request API data when needed
7079
+ // Effect to request dynamic option data (API / ENTITY_DATA) from the consumer.
7080
+ // Lazy: only fires once the cell is activated for editing, not on grid load.
7081
+ // Fetched once per column — reuses the store cache for every other row.
6972
7082
  effect(() => {
7083
+ const active = this.isActive();
6973
7084
  const cfg = this.config();
6974
7085
  const store = this.eruGridStore();
6975
- if (cfg && ((cfg.option_type === 'API' && cfg.api_name) || (cfg.option_type === 'ENTITY_DATA' && cfg.entity_name)) && store) {
6976
- let apiName = cfg.api_name || '';
6977
- if (cfg.option_type === 'ENTITY_DATA') {
6978
- apiName = cfg.entity_name || '';
6979
- }
6980
- const currentRequests = store.getDynamicDataRequest() || [];
6981
- if (!currentRequests.includes(apiName)) {
6982
- store.setDynamicDataRequest(apiName);
6983
- }
7086
+ const cache = store?.dynamicData();
7087
+ if (!active) {
7088
+ return;
7089
+ }
7090
+ if (!cfg || !store) {
7091
+ return;
7092
+ }
7093
+ if (cfg.option_type !== 'API' && cfg.option_type !== 'ENTITY_DATA') {
7094
+ return;
7095
+ }
7096
+ const key = cfg.option_type === 'ENTITY_DATA' ? (cfg.entity_name || '') : (cfg.api_name || '');
7097
+ if (!key) {
7098
+ return;
6984
7099
  }
7100
+ // Already fetched for this column, or a fetch is already pending → reuse it.
7101
+ if ((cache && cache.has(key)) || store.hasDynamicDataRequest(key)) {
7102
+ return;
7103
+ }
7104
+ store.setDynamicDataRequest({
7105
+ key,
7106
+ optionType: cfg.option_type,
7107
+ entityName: cfg.entity_name,
7108
+ fieldName: cfg.field_name,
7109
+ apiName: cfg.api_name,
7110
+ apiField: cfg.api_field,
7111
+ search: untracked(() => this.searchText()) || ''
7112
+ });
6985
7113
  });
6986
7114
  }
6987
7115
  ngOnInit() {
@@ -7182,7 +7310,7 @@ class StatusComponent {
7182
7310
  return `#${toHex(darkerR)}${toHex(darkerG)}${toHex(darkerB)}`;
7183
7311
  }
7184
7312
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: StatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7185
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: StatusComponent, isStandalone: true, selector: "eru-status", 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" }, 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=\"status-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"status-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || 'Select status...'\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"status-panel\"\n class=\"status-input\"\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 <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 placeholder=\"filter options...\"\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 </mat-option>\n\n <mat-option [value]=\"null\">\n None\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 <div class=\"status-option-content\">\n @if(option.color) {\n <span class=\"status-option-indicator\"\n [style.background-color]=\"option.color\"\n [style.border-color]=\"getDarkerColor(option.color)\"></span>\n }\n <span class=\"status-option-label\">{{ option.label }}</span>\n </div>\n </mat-option>\n }\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n @if(currentValue()) {\n <div \n class=\"status-display\"\n [style.background-color]=\"statusColors().background\"\n [style.border-color]=\"statusColors().border\"\n [style.color]=\"statusColors().text\"\n (dblclick)=\"onActivate()\">\n <div class=\"status-display-content\">\n @if (isDrillable()) {\n <span class=\"status-text drillable-value\" (click)=\"onDrillableClick($event)\">\n {{statusDisplay().text}}\n </span>\n } @else {\n <span class=\"status-text\">\n {{statusDisplay().text}}\n </span>\n }\n </div>\n </div>\n } @else {\n <div class=\"status-empty\" (dblclick)=\"onActivate()\"></div>\n }\n}\n\n", styles: [".status-form-field{width:100%}.status-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.status-input{padding-left:4px}.status-container{width:100%}.status-empty{width:100%;min-height:30px;cursor:pointer}.status-display{cursor:pointer;width:fit-content;max-width:calc(100% - 12px);min-height:auto;border-radius:var(--grid-pill-radius, 4px);border:1px solid;transition:all .2s ease;display:inline-flex;align-items:center;justify-content:center;padding:var(--grid-pill-padding-y, 2px) var(--grid-pill-padding-x, 10px);font-size:var(--grid-pill-font-size, inherit);font-weight:var(--grid-pill-font-weight, 500);box-sizing:border-box;cursor:default;margin:4px 6px}.status-display:hover{opacity:.9}.status-display-content{cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px;width:100%}.status-text{text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-color-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0}.drillable-value{color:inherit;text-decoration:underline;cursor:pointer}.drillable-value:hover{opacity:.8}.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}.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}.status-panel{min-width:150px!important}.status-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.status-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.status-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:last-of-type mat-pseudo-checkbox,.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .status-option-content{display:flex;align-items:center;gap:8px;width:100%}mat-option .status-option-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0;border:1.5px solid}mat-option .status-option-label{flex:1;color:var(--grid-on-surface, #1d1b20);font-size:var(--grid-font-size-body, 12px);font-weight:400}\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$2.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$2.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: MatButtonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7313
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: StatusComponent, isStandalone: true, selector: "eru-status", 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" }, 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=\"status-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"status-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || 'Select status...'\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"status-panel\"\n class=\"status-input\"\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 <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 placeholder=\"filter options...\"\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 </mat-option>\n\n <mat-option [value]=\"null\">\n None\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 <div class=\"status-option-content\">\n @if(option.color) {\n <span class=\"status-option-indicator\"\n [style.background-color]=\"option.color\"\n [style.border-color]=\"getDarkerColor(option.color)\"></span>\n }\n <span class=\"status-option-label\">{{ option.label }}</span>\n </div>\n </mat-option>\n }\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n @if(currentValue()) {\n <div \n class=\"status-display\"\n [style.background-color]=\"statusColors().background\"\n [style.border-color]=\"statusColors().border\"\n [style.color]=\"statusColors().text\"\n (dblclick)=\"onActivate()\">\n <div class=\"status-display-content\">\n @if (isDrillable()) {\n <span class=\"status-text drillable-value\" (click)=\"onDrillableClick($event)\">\n {{statusDisplay().text}}\n </span>\n } @else {\n <span class=\"status-text\">\n {{statusDisplay().text}}\n </span>\n }\n </div>\n </div>\n } @else {\n <div class=\"status-empty\" (dblclick)=\"onActivate()\"></div>\n }\n}\n\n", styles: [".status-form-field{width:100%}.status-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.status-input{padding-left:4px}.status-container{width:100%}.status-empty{width:100%;min-height:30px;cursor:pointer}.status-display{cursor:pointer;width:auto;min-height:auto;border-radius:var(--grid-pill-radius, 4px);border:1px solid;transition:all .2s ease;display:flex;align-items:center;justify-content:center;padding:var(--grid-pill-padding-y, 2px) var(--grid-pill-padding-x, 10px);font-size:var(--grid-pill-font-size, inherit);font-weight:var(--grid-pill-font-weight, 500);box-sizing:border-box;cursor:default;margin:4px 6px}.status-display:hover{opacity:.9}.status-display-content{cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px;width:100%}.status-text{text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-color-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0}.drillable-value{color:inherit;text-decoration:underline;cursor:pointer}.drillable-value:hover{opacity:.8}.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}.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}.status-panel{min-width:150px!important}.status-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.status-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.status-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:last-of-type mat-pseudo-checkbox,.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .status-option-content{display:flex;align-items:center;gap:8px;width:100%}mat-option .status-option-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0;border:1.5px solid}mat-option .status-option-label{flex:1;color:var(--grid-on-surface, #1d1b20);font-size:var(--grid-font-size-body, 12px);font-weight:400}\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$2.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$2.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: MatButtonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
7186
7314
  }
7187
7315
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: StatusComponent, decorators: [{
7188
7316
  type: Component,
@@ -7193,7 +7321,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
7193
7321
  MatInputModule,
7194
7322
  MatOptionModule,
7195
7323
  MatButtonModule
7196
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"status-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"status-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || 'Select status...'\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"status-panel\"\n class=\"status-input\"\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 <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 placeholder=\"filter options...\"\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 </mat-option>\n\n <mat-option [value]=\"null\">\n None\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 <div class=\"status-option-content\">\n @if(option.color) {\n <span class=\"status-option-indicator\"\n [style.background-color]=\"option.color\"\n [style.border-color]=\"getDarkerColor(option.color)\"></span>\n }\n <span class=\"status-option-label\">{{ option.label }}</span>\n </div>\n </mat-option>\n }\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n @if(currentValue()) {\n <div \n class=\"status-display\"\n [style.background-color]=\"statusColors().background\"\n [style.border-color]=\"statusColors().border\"\n [style.color]=\"statusColors().text\"\n (dblclick)=\"onActivate()\">\n <div class=\"status-display-content\">\n @if (isDrillable()) {\n <span class=\"status-text drillable-value\" (click)=\"onDrillableClick($event)\">\n {{statusDisplay().text}}\n </span>\n } @else {\n <span class=\"status-text\">\n {{statusDisplay().text}}\n </span>\n }\n </div>\n </div>\n } @else {\n <div class=\"status-empty\" (dblclick)=\"onActivate()\"></div>\n }\n}\n\n", styles: [".status-form-field{width:100%}.status-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.status-input{padding-left:4px}.status-container{width:100%}.status-empty{width:100%;min-height:30px;cursor:pointer}.status-display{cursor:pointer;width:fit-content;max-width:calc(100% - 12px);min-height:auto;border-radius:var(--grid-pill-radius, 4px);border:1px solid;transition:all .2s ease;display:inline-flex;align-items:center;justify-content:center;padding:var(--grid-pill-padding-y, 2px) var(--grid-pill-padding-x, 10px);font-size:var(--grid-pill-font-size, inherit);font-weight:var(--grid-pill-font-weight, 500);box-sizing:border-box;cursor:default;margin:4px 6px}.status-display:hover{opacity:.9}.status-display-content{cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px;width:100%}.status-text{text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-color-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0}.drillable-value{color:inherit;text-decoration:underline;cursor:pointer}.drillable-value:hover{opacity:.8}.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}.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}.status-panel{min-width:150px!important}.status-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.status-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.status-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:last-of-type mat-pseudo-checkbox,.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .status-option-content{display:flex;align-items:center;gap:8px;width:100%}mat-option .status-option-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0;border:1.5px solid}mat-option .status-option-label{flex:1;color:var(--grid-on-surface, #1d1b20);font-size:var(--grid-font-size-body, 12px);font-weight:400}\n"] }]
7324
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"status-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"status-container\">\n <mat-select\n [placeholder]=\"getProperty('placeholder') || 'Select status...'\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"status-panel\"\n class=\"status-input\"\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 <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 placeholder=\"filter options...\"\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 </mat-option>\n\n <mat-option [value]=\"null\">\n None\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 <div class=\"status-option-content\">\n @if(option.color) {\n <span class=\"status-option-indicator\"\n [style.background-color]=\"option.color\"\n [style.border-color]=\"getDarkerColor(option.color)\"></span>\n }\n <span class=\"status-option-label\">{{ option.label }}</span>\n </div>\n </mat-option>\n }\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n @if(currentValue()) {\n <div \n class=\"status-display\"\n [style.background-color]=\"statusColors().background\"\n [style.border-color]=\"statusColors().border\"\n [style.color]=\"statusColors().text\"\n (dblclick)=\"onActivate()\">\n <div class=\"status-display-content\">\n @if (isDrillable()) {\n <span class=\"status-text drillable-value\" (click)=\"onDrillableClick($event)\">\n {{statusDisplay().text}}\n </span>\n } @else {\n <span class=\"status-text\">\n {{statusDisplay().text}}\n </span>\n }\n </div>\n </div>\n } @else {\n <div class=\"status-empty\" (dblclick)=\"onActivate()\"></div>\n }\n}\n\n", styles: [".status-form-field{width:100%}.status-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.status-input{padding-left:4px}.status-container{width:100%}.status-empty{width:100%;min-height:30px;cursor:pointer}.status-display{cursor:pointer;width:auto;min-height:auto;border-radius:var(--grid-pill-radius, 4px);border:1px solid;transition:all .2s ease;display:flex;align-items:center;justify-content:center;padding:var(--grid-pill-padding-y, 2px) var(--grid-pill-padding-x, 10px);font-size:var(--grid-pill-font-size, inherit);font-weight:var(--grid-pill-font-weight, 500);box-sizing:border-box;cursor:default;margin:4px 6px}.status-display:hover{opacity:.9}.status-display-content{cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px;width:100%}.status-text{text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-color-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0}.drillable-value{color:inherit;text-decoration:underline;cursor:pointer}.drillable-value:hover{opacity:.8}.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}.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}.status-panel{min-width:150px!important}.status-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.status-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.status-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:last-of-type mat-pseudo-checkbox,.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .status-option-content{display:flex;align-items:center;gap:8px;width:100%}mat-option .status-option-indicator{width:12px;height:12px;border-radius:50%;display:inline-block;flex-shrink:0;border:1.5px solid}mat-option .status-option-label{flex:1;color:var(--grid-on-surface, #1d1b20);font-size:var(--grid-font-size-body, 12px);font-weight:400}\n"] }]
7197
7325
  }], ctorParameters: () => [], propDecorators: { selectContainer: [{
7198
7326
  type: ViewChild,
7199
7327
  args: ['selectContainer', { static: false }]
@@ -7322,18 +7450,27 @@ class TagComponent {
7322
7450
  this.currentValue.set([]);
7323
7451
  }
7324
7452
  });
7325
- // Effect to request API data when needed
7453
+ // Effect to request API data when needed (lazy: only once activated for editing)
7326
7454
  effect(() => {
7455
+ const active = this.isActive();
7327
7456
  const cfg = this.config();
7328
7457
  const store = this.eruGridStore();
7329
- if (cfg && ((cfg.option_type === 'API' && cfg.api_name) || (cfg.option_type === 'ENTITY_DATA' && cfg.entity_name)) && store) {
7458
+ const cache = store?.dynamicData();
7459
+ if (active && cfg && ((cfg.option_type === 'API' && cfg.api_name) || (cfg.option_type === 'ENTITY_DATA' && cfg.entity_name)) && store) {
7330
7460
  let apiName = cfg.api_name || '';
7331
7461
  if (cfg.option_type === 'ENTITY_DATA') {
7332
7462
  apiName = cfg.entity_name || '';
7333
7463
  }
7334
- const currentRequests = store.getDynamicDataRequest() || [];
7335
- if (!currentRequests.includes(apiName)) {
7336
- store.setDynamicDataRequest(apiName);
7464
+ // Fetch once per column: skip if already cached or a request is pending.
7465
+ if (!(cache && cache.has(apiName)) && !store.hasDynamicDataRequest(apiName)) {
7466
+ store.setDynamicDataRequest({
7467
+ key: apiName,
7468
+ optionType: cfg.option_type,
7469
+ entityName: cfg.entity_name,
7470
+ fieldName: cfg.field_name,
7471
+ apiName: cfg.api_name,
7472
+ apiField: cfg.api_field
7473
+ });
7337
7474
  }
7338
7475
  }
7339
7476
  });
@@ -7704,14 +7841,16 @@ class PeopleComponent {
7704
7841
  }
7705
7842
  });
7706
7843
  // Effect to request API data when needed (people component always uses API)
7844
+ // Lazy: only once activated for editing, not on grid load.
7707
7845
  effect(() => {
7846
+ const active = this.isActive();
7708
7847
  const store = this.eruGridStore();
7709
- if (store) {
7848
+ const cache = store?.dynamicData();
7849
+ if (active && store) {
7710
7850
  const apiName = 'people';
7711
- const currentRequests = store.getDynamicDataRequest() || [];
7712
- // Request data if not already requested
7713
- if (!currentRequests.includes(apiName)) {
7714
- store.setDynamicDataRequest(apiName);
7851
+ // Fetch once per column: skip if already cached or a request is pending.
7852
+ if (!(cache && cache.has(apiName)) && !store.hasDynamicDataRequest(apiName)) {
7853
+ store.setDynamicDataRequest({ key: apiName, optionType: 'API', apiName });
7715
7854
  }
7716
7855
  }
7717
7856
  });
@@ -7900,7 +8039,7 @@ class PriorityComponent {
7900
8039
  const options = cfg.options || [];
7901
8040
  let processedOptions = options
7902
8041
  .map((value) => ({
7903
- value: value.name || value.value,
8042
+ value: value.name || value.value || value.label,
7904
8043
  label: value.label || value.name || value.value,
7905
8044
  color: value.color
7906
8045
  }));
@@ -7917,7 +8056,7 @@ class PriorityComponent {
7917
8056
  const cfg = this.config();
7918
8057
  if (!cfg || !cfg.options)
7919
8058
  return null;
7920
- const option = cfg.options.find((opt) => (opt.name || opt.value) === value);
8059
+ const option = cfg.options.find((opt) => (opt.name || opt.value || opt.label) === value);
7921
8060
  return option || null;
7922
8061
  }, ...(ngDevMode ? [{ debugName: "priorityIcon" }] : []));
7923
8062
  priorityColor = computed(() => {
@@ -7927,7 +8066,7 @@ class PriorityComponent {
7927
8066
  const cfg = this.config();
7928
8067
  if (!cfg || !cfg.options)
7929
8068
  return '';
7930
- const option = cfg.options.find((opt) => (opt.name || opt.value) === value);
8069
+ const option = cfg.options.find((opt) => (opt.name || opt.value || opt.label) === value);
7931
8070
  return option?.color || '';
7932
8071
  }, ...(ngDevMode ? [{ debugName: "priorityColor" }] : []));
7933
8072
  constructor() {
@@ -7936,18 +8075,27 @@ class PriorityComponent {
7936
8075
  const value = this.value();
7937
8076
  this.currentValue.set(value);
7938
8077
  });
7939
- // Effect to request API data when needed
8078
+ // Effect to request API data when needed (lazy: only once activated for editing)
7940
8079
  effect(() => {
8080
+ const active = this.isActive();
7941
8081
  const cfg = this.config();
7942
8082
  const store = this.eruGridStore();
7943
- if (cfg && ((cfg.option_type === 'API' && cfg.api_name) || (cfg.option_type === 'ENTITY_DATA' && cfg.entity_name)) && store) {
8083
+ const cache = store?.dynamicData();
8084
+ if (active && cfg && ((cfg.option_type === 'API' && cfg.api_name) || (cfg.option_type === 'ENTITY_DATA' && cfg.entity_name)) && store) {
7944
8085
  let apiName = cfg.api_name || '';
7945
8086
  if (cfg.option_type === 'ENTITY_DATA') {
7946
8087
  apiName = cfg.entity_name || '';
7947
8088
  }
7948
- const currentRequests = store.getDynamicDataRequest() || [];
7949
- if (!currentRequests.includes(apiName)) {
7950
- store.setDynamicDataRequest(apiName);
8089
+ // Fetch once per column: skip if already cached or a request is pending.
8090
+ if (!(cache && cache.has(apiName)) && !store.hasDynamicDataRequest(apiName)) {
8091
+ store.setDynamicDataRequest({
8092
+ key: apiName,
8093
+ optionType: cfg.option_type,
8094
+ entityName: cfg.entity_name,
8095
+ fieldName: cfg.field_name,
8096
+ apiName: cfg.api_name,
8097
+ apiField: cfg.api_field
8098
+ });
7951
8099
  }
7952
8100
  }
7953
8101
  });
@@ -8064,14 +8212,14 @@ class PriorityComponent {
8064
8212
  const cfg = this.config();
8065
8213
  if (!cfg || !cfg.options)
8066
8214
  return String(value);
8067
- const option = cfg.options.find((opt) => (opt.name || opt.value) === value);
8215
+ const option = cfg.options.find((opt) => (opt.name || opt.value || opt.label) === value);
8068
8216
  return option ? (option.label || option.name || option.value) : String(value);
8069
8217
  }
8070
8218
  trackByValueAndIndex(index, option) {
8071
8219
  return `${option.value}_${index}`;
8072
8220
  }
8073
8221
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PriorityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8074
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: PriorityComponent, isStandalone: true, selector: "eru-priority", 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" }, viewQueries: [{ propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true }, { propertyName: "matSelect", first: true, predicate: ["matSelect"], descendants: true }], ngImport: i0, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"priority-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"priority-container\">\n <mat-select\n #matSelect\n [placeholder]=\"getProperty('placeholder') || ''\"\n [multiple]=\"false\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"priority-panel\"\n (selectionChange)=\"onValueChange($event.value)\"\n (blur)=\"onBlur($event)\"\n (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n \n <mat-select-trigger>\n @if(priorityIcon()) {\n <span class=\"priority-trigger\">\n <mat-icon class=\"priority-icon-trigger\" [style.color]=\"priorityColor()\">flag</mat-icon>\n <span>{{ getSelectedLabel() }}</span>\n </span>\n } @else {\n <span>{{ getSelectedLabel() }}</span>\n }\n </mat-select-trigger>\n \n <mat-option disabled class=\"search-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\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 placeholder=\"filter options...\"\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 </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\">\n <span class=\"priority-option\">\n <mat-icon class=\"priority-icon\" [style.color]=\"getOptionColor(option)\">flag</mat-icon>\n <span class=\"priority-label\">{{ option.label }}</span>\n </span>\n </mat-option>\n }\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n <div\n class=\"priority-display\"\n [class.priority-display-editable]=\"isEditable()\"\n (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{currentValue()}}</span>\n </span>\n } @else {\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{currentValue()}}</span>\n }\n </div>\n}\n", styles: [".priority-form-field{width:100%}.priority-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.priority-container{width:100%}.priority-trigger{display:flex;align-items:center;gap:8px;width:100%}.priority-icon-trigger{width:16px;height:16px;padding-left:2px;font-size:16px;line-height:16px;flex-shrink:0}.priority-display{width:100%;padding:8px 12px;min-height:30px;display:flex;align-items:center;gap:8px;cursor:default}.priority-display.priority-display-editable{cursor:pointer}.priority-display.priority-display-editable:hover{background-color:#0000000a}.priority-icon-display{width:16px;height:16px;font-size:16px;line-height:16px}.priority-dot{display:inline-block;width:var(--grid-priority-dot-size, 8px);height:var(--grid-priority-dot-size, 8px);border-radius:50%;flex-shrink:0}.priority-label-text{line-height:1.2}.drillable-value{display:flex;align-items:center;gap:8px;color:#1976d2;cursor:pointer;text-decoration:underline}.drillable-value:hover{color:#1565c0}.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}.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}.priority-panel{min-width:150px!important}.priority-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.priority-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.priority-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .priority-option{display:flex;align-items:center;gap:8px;width:100%}mat-option .priority-icon{width:16px;height:16px;font-size:16px;line-height:16px;flex-shrink:0}mat-option .priority-label{flex:1}\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$2.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: "directive", type: i2$2.MatSelectTrigger, selector: "mat-select-trigger" }, { kind: "component", type: i2$2.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: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
8222
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: PriorityComponent, isStandalone: true, selector: "eru-priority", 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" }, viewQueries: [{ propertyName: "selectContainer", first: true, predicate: ["selectContainer"], descendants: true }, { propertyName: "matSelect", first: true, predicate: ["matSelect"], descendants: true }], ngImport: i0, template: "@if(isActive()) {\n<mat-form-field [appearance]=\"getProperty('appearance') || 'outline'\" class=\"priority-form-field\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"priority-container\">\n <mat-select #matSelect [placeholder]=\"getProperty('placeholder') || ''\" [multiple]=\"false\"\n [disabled]=\"getProperty('disabled') || !isEditable()\" [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\" [compareWith]=\"compareWith\" panelClass=\"priority-panel\"\n (selectionChange)=\"onValueChange($event.value)\" (blur)=\"onBlur($event)\" (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n\n <mat-select-trigger>\n @if(priorityIcon()) {\n <span class=\"priority-trigger\">\n <mat-icon class=\"priority-icon-trigger\" [style.color]=\"priorityColor()\">flag</mat-icon>\n <span>{{ getSelectedLabel() }}</span>\n </span>\n } @else {\n <span>{{ getSelectedLabel() }}</span>\n }\n </mat-select-trigger>\n\n <mat-option disabled class=\"search-option\" (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-form-field [appearance]=\"getProperty('appearance') || 'outline'\" class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input matInput type=\"text\" class=\"search-input\" [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\" (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\">\n <span class=\"priority-option\">\n <mat-icon class=\"priority-icon\" [style.color]=\"getOptionColor(option)\">flag</mat-icon>\n <span class=\"priority-label\">{{ option.label }}</span>\n </span>\n </mat-option>\n }\n </mat-select>\n </div>\n</mat-form-field>\n} @else {\n<div class=\"priority-display\" [class.priority-display-editable]=\"isEditable()\" (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{getSelectedLabel()}}</span>\n </span>\n } @else {\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{getSelectedLabel()}}</span>\n }\n</div>\n}", styles: [".priority-form-field{width:100%}.priority-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.priority-container{width:100%}.priority-trigger{display:flex;align-items:center;gap:8px;width:100%}.priority-icon-trigger{width:16px;height:16px;padding-left:2px;font-size:16px;line-height:16px;flex-shrink:0}.priority-display{width:100%;padding:8px 12px;min-height:30px;display:flex;align-items:center;gap:8px;cursor:default}.priority-display.priority-display-editable{cursor:pointer}.priority-display.priority-display-editable:hover{background-color:#0000000a}.priority-icon-display{width:16px;height:16px;font-size:16px;line-height:16px}.priority-dot{display:inline-block;width:var(--grid-priority-dot-size, 8px);height:var(--grid-priority-dot-size, 8px);border-radius:50%;flex-shrink:0}.priority-label-text{line-height:1.2}.drillable-value{display:flex;align-items:center;gap:8px;color:#1976d2;cursor:pointer;text-decoration:underline}.drillable-value:hover{color:#1565c0}.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}.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}.priority-panel{min-width:150px!important}.priority-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.priority-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.priority-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .priority-option{display:flex;align-items:center;gap:8px;width:100%}mat-option .priority-icon{width:16px;height:16px;font-size:16px;line-height:16px;flex-shrink:0}mat-option .priority-label{flex:1}\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$2.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: "directive", type: i2$2.MatSelectTrigger, selector: "mat-select-trigger" }, { kind: "component", type: i2$2.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: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
8075
8223
  }
8076
8224
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: PriorityComponent, decorators: [{
8077
8225
  type: Component,
@@ -8082,7 +8230,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
8082
8230
  MatInputModule,
8083
8231
  MatOptionModule,
8084
8232
  MatIconModule
8085
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if(isActive()) {\n <mat-form-field \n [appearance]=\"getProperty('appearance') || 'outline'\"\n class=\"priority-form-field\"\n (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"priority-container\">\n <mat-select\n #matSelect\n [placeholder]=\"getProperty('placeholder') || ''\"\n [multiple]=\"false\"\n [disabled]=\"getProperty('disabled') || !isEditable()\"\n [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\"\n [compareWith]=\"compareWith\"\n panelClass=\"priority-panel\"\n (selectionChange)=\"onValueChange($event.value)\"\n (blur)=\"onBlur($event)\"\n (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n \n <mat-select-trigger>\n @if(priorityIcon()) {\n <span class=\"priority-trigger\">\n <mat-icon class=\"priority-icon-trigger\" [style.color]=\"priorityColor()\">flag</mat-icon>\n <span>{{ getSelectedLabel() }}</span>\n </span>\n } @else {\n <span>{{ getSelectedLabel() }}</span>\n }\n </mat-select-trigger>\n \n <mat-option disabled class=\"search-option\"\n (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\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 placeholder=\"filter options...\"\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 </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\">\n <span class=\"priority-option\">\n <mat-icon class=\"priority-icon\" [style.color]=\"getOptionColor(option)\">flag</mat-icon>\n <span class=\"priority-label\">{{ option.label }}</span>\n </span>\n </mat-option>\n }\n </mat-select>\n </div>\n </mat-form-field>\n} @else {\n <div\n class=\"priority-display\"\n [class.priority-display-editable]=\"isEditable()\"\n (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{currentValue()}}</span>\n </span>\n } @else {\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{currentValue()}}</span>\n }\n </div>\n}\n", styles: [".priority-form-field{width:100%}.priority-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.priority-container{width:100%}.priority-trigger{display:flex;align-items:center;gap:8px;width:100%}.priority-icon-trigger{width:16px;height:16px;padding-left:2px;font-size:16px;line-height:16px;flex-shrink:0}.priority-display{width:100%;padding:8px 12px;min-height:30px;display:flex;align-items:center;gap:8px;cursor:default}.priority-display.priority-display-editable{cursor:pointer}.priority-display.priority-display-editable:hover{background-color:#0000000a}.priority-icon-display{width:16px;height:16px;font-size:16px;line-height:16px}.priority-dot{display:inline-block;width:var(--grid-priority-dot-size, 8px);height:var(--grid-priority-dot-size, 8px);border-radius:50%;flex-shrink:0}.priority-label-text{line-height:1.2}.drillable-value{display:flex;align-items:center;gap:8px;color:#1976d2;cursor:pointer;text-decoration:underline}.drillable-value:hover{color:#1565c0}.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}.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}.priority-panel{min-width:150px!important}.priority-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.priority-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.priority-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .priority-option{display:flex;align-items:center;gap:8px;width:100%}mat-option .priority-icon{width:16px;height:16px;font-size:16px;line-height:16px;flex-shrink:0}mat-option .priority-label{flex:1}\n"] }]
8233
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "@if(isActive()) {\n<mat-form-field [appearance]=\"getProperty('appearance') || 'outline'\" class=\"priority-form-field\"\n (click)=\"$event.stopPropagation()\" (mousedown)=\"$event.stopPropagation()\">\n <div #selectContainer class=\"priority-container\">\n <mat-select #matSelect [placeholder]=\"getProperty('placeholder') || ''\" [multiple]=\"false\"\n [disabled]=\"getProperty('disabled') || !isEditable()\" [required]=\"hasRequiredValidation()\"\n [value]=\"currentValue()\" [compareWith]=\"compareWith\" panelClass=\"priority-panel\"\n (selectionChange)=\"onValueChange($event.value)\" (blur)=\"onBlur($event)\" (openedChange)=\"onOpenedChange($event)\"\n (click)=\"$event.stopPropagation()\">\n\n <mat-select-trigger>\n @if(priorityIcon()) {\n <span class=\"priority-trigger\">\n <mat-icon class=\"priority-icon-trigger\" [style.color]=\"priorityColor()\">flag</mat-icon>\n <span>{{ getSelectedLabel() }}</span>\n </span>\n } @else {\n <span>{{ getSelectedLabel() }}</span>\n }\n </mat-select-trigger>\n\n <mat-option disabled class=\"search-option\" (click)=\"$event.stopPropagation(); $event.preventDefault()\"\n (mousedown)=\"$event.stopPropagation(); $event.preventDefault()\">\n <mat-form-field [appearance]=\"getProperty('appearance') || 'outline'\" class=\"search-form-field\">\n <mat-label>Search</mat-label>\n <input matInput type=\"text\" class=\"search-input\" [value]=\"searchText()\"\n (input)=\"onSearchChange($any($event.target).value)\" (click)=\"$event.stopPropagation()\"\n (mousedown)=\"$event.stopPropagation()\" (keydown)=\"$event.stopPropagation()\"\n (focus)=\"$event.stopPropagation()\">\n </mat-form-field>\n </mat-option>\n\n @for (option of filteredOptions(); track trackByValueAndIndex($index, option)) {\n <mat-option [value]=\"option.value\">\n <span class=\"priority-option\">\n <mat-icon class=\"priority-icon\" [style.color]=\"getOptionColor(option)\">flag</mat-icon>\n <span class=\"priority-label\">{{ option.label }}</span>\n </span>\n </mat-option>\n }\n </mat-select>\n </div>\n</mat-form-field>\n} @else {\n<div class=\"priority-display\" [class.priority-display-editable]=\"isEditable()\" (dblclick)=\"onActivate()\">\n @if (isDrillable()) {\n <span class=\"drillable-value\" (click)=\"onDrillableClick($event)\">\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{getSelectedLabel()}}</span>\n </span>\n } @else {\n @if(priorityIcon()) {\n <span class=\"priority-dot\" [style.background-color]=\"priorityColor()\"></span>\n }\n <span class=\"priority-label-text\">{{getSelectedLabel()}}</span>\n }\n</div>\n}", styles: [".priority-form-field{width:100%}.priority-form-field .mat-mdc-form-field-subscript-wrapper{display:none}.priority-container{width:100%}.priority-trigger{display:flex;align-items:center;gap:8px;width:100%}.priority-icon-trigger{width:16px;height:16px;padding-left:2px;font-size:16px;line-height:16px;flex-shrink:0}.priority-display{width:100%;padding:8px 12px;min-height:30px;display:flex;align-items:center;gap:8px;cursor:default}.priority-display.priority-display-editable{cursor:pointer}.priority-display.priority-display-editable:hover{background-color:#0000000a}.priority-icon-display{width:16px;height:16px;font-size:16px;line-height:16px}.priority-dot{display:inline-block;width:var(--grid-priority-dot-size, 8px);height:var(--grid-priority-dot-size, 8px);border-radius:50%;flex-shrink:0}.priority-label-text{line-height:1.2}.drillable-value{display:flex;align-items:center;gap:8px;color:#1976d2;cursor:pointer;text-decoration:underline}.drillable-value:hover{color:#1565c0}.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}.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}.priority-panel{min-width:150px!important}.priority-panel .search-option .mat-mdc-option,.mat-mdc-select-panel .search-option .mat-mdc-option{min-height:auto!important;padding:2px 4px!important}.priority-panel .mdc-list-item--disabled,.mat-mdc-select-panel .mdc-list-item--disabled{pointer-events:auto!important;cursor:default!important}.priority-panel .mdc-list-item--disabled:hover,.mat-mdc-select-panel .mdc-list-item--disabled:hover{background:transparent!important}.mat-select-panel-animations-enabled mat-option:first-of-type mat-pseudo-checkbox{display:none!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 .priority-option{display:flex;align-items:center;gap:8px;width:100%}mat-option .priority-icon{width:16px;height:16px;font-size:16px;line-height:16px;flex-shrink:0}mat-option .priority-label{flex:1}\n"] }]
8086
8234
  }], ctorParameters: () => [], propDecorators: { selectContainer: [{
8087
8235
  type: ViewChild,
8088
8236
  args: ['selectContainer', { static: false }]
@@ -10149,6 +10297,208 @@ const PRESET_CONFIG_DEFAULTS = {
10149
10297
  financial: { showColumnLines: false, showRowLines: true, headerRowHeight: 40, dataRowHeight: 34 },
10150
10298
  elevated: { showColumnLines: false, showRowLines: true, headerRowHeight: 50, dataRowHeight: 46 },
10151
10299
  };
10300
+ const DATA_TYPES = [
10301
+ 'number',
10302
+ 'textbox',
10303
+ 'currency',
10304
+ 'date',
10305
+ 'datetime',
10306
+ 'duration',
10307
+ 'dropdown_single_select',
10308
+ 'dropdown_multi_select',
10309
+ 'location',
10310
+ 'email',
10311
+ 'people',
10312
+ 'checkbox',
10313
+ 'phone',
10314
+ 'priority',
10315
+ 'status',
10316
+ 'progress',
10317
+ 'attachment',
10318
+ 'tag',
10319
+ 'rating',
10320
+ 'website',
10321
+ ];
10322
+
10323
+ const UNIVERSAL_FIELDS = [
10324
+ { key: 'label', label: 'Label', control: 'text' },
10325
+ {
10326
+ key: 'datatype',
10327
+ label: 'Data type',
10328
+ control: 'select',
10329
+ options: DATA_TYPES.map(d => ({ value: d, label: d })),
10330
+ },
10331
+ { key: 'required', label: 'Required', control: 'checkbox' },
10332
+ ];
10333
+ const NUMBER_FIELDS = [
10334
+ { key: 'decimal', label: 'Decimal places', control: 'number' },
10335
+ { key: 'symbol', label: 'Symbol', control: 'text' },
10336
+ {
10337
+ key: 'seperator',
10338
+ label: 'Separator',
10339
+ control: 'select',
10340
+ options: [
10341
+ { value: 'none', label: 'None' },
10342
+ { value: 'thousands', label: 'Thousands' },
10343
+ { value: 'millions', label: 'Millions' },
10344
+ ],
10345
+ },
10346
+ { key: 'num_val', label: 'Limit value', control: 'number' },
10347
+ {
10348
+ key: 'num_val_check',
10349
+ label: 'Limit type',
10350
+ control: 'select',
10351
+ options: [
10352
+ { value: 'MIN', label: 'Minimum' },
10353
+ { value: 'MAX', label: 'Maximum' },
10354
+ ],
10355
+ },
10356
+ { key: 'dynamic_number', label: 'Abbreviate (k, L, Cr)', control: 'checkbox' },
10357
+ {
10358
+ key: 'display_number_as',
10359
+ label: 'Display as',
10360
+ control: 'select',
10361
+ options: [
10362
+ { value: 'lacs', label: 'Lacs' },
10363
+ { value: 'mn', label: 'Millions' },
10364
+ ],
10365
+ },
10366
+ ];
10367
+ const OPTION_FIELDS = [
10368
+ {
10369
+ key: 'option_type',
10370
+ label: 'Option source',
10371
+ control: 'select',
10372
+ options: [
10373
+ { value: 'STATIC', label: 'Static' },
10374
+ { value: 'API', label: 'API' },
10375
+ { value: 'ENTITY_DATA', label: 'Entity data' },
10376
+ ],
10377
+ },
10378
+ {
10379
+ key: 'options',
10380
+ label: 'Options (one per line)',
10381
+ control: 'list',
10382
+ showWhen: f => f.option_type === 'STATIC',
10383
+ },
10384
+ {
10385
+ key: 'entity_name',
10386
+ label: 'Entity name',
10387
+ control: 'text',
10388
+ showWhen: f => f.option_type === 'ENTITY_DATA',
10389
+ },
10390
+ {
10391
+ key: 'field_name',
10392
+ label: 'Field name',
10393
+ control: 'text',
10394
+ showWhen: f => f.option_type === 'ENTITY_DATA',
10395
+ },
10396
+ {
10397
+ key: 'api_name',
10398
+ label: 'API name',
10399
+ control: 'text',
10400
+ showWhen: f => f.option_type === 'API',
10401
+ },
10402
+ {
10403
+ key: 'api_field',
10404
+ label: 'Field name',
10405
+ control: 'text',
10406
+ showWhen: f => f.option_type === 'API',
10407
+ },
10408
+ ];
10409
+ const DATATYPE_FIELDS = {
10410
+ number: NUMBER_FIELDS,
10411
+ currency: NUMBER_FIELDS,
10412
+ dropdown_single_select: OPTION_FIELDS,
10413
+ dropdown_multi_select: OPTION_FIELDS,
10414
+ tag: OPTION_FIELDS,
10415
+ priority: OPTION_FIELDS,
10416
+ status: [
10417
+ { key: 'open_status', label: 'Open statuses (one per line)', control: 'list' },
10418
+ { key: 'close_status', label: 'Close statuses (one per line)', control: 'list' },
10419
+ ],
10420
+ rating: [
10421
+ { key: 'start_value', label: 'Scale start', control: 'number' },
10422
+ { key: 'end_value', label: 'Scale end', control: 'number' },
10423
+ { key: 'emoji_value', label: 'Icon', control: 'text' },
10424
+ ],
10425
+ attachment: [
10426
+ { key: 'max_files', label: 'Max files', control: 'number' },
10427
+ { key: 'allowed_file_types', label: 'Allowed types (one per line)', control: 'list' },
10428
+ { key: 'maxFileSize', label: 'Max file size (bytes)', control: 'number' },
10429
+ ],
10430
+ phone: [{ key: 'default_country', label: 'Default country (ISO)', control: 'text' }],
10431
+ textbox: [{ key: 'data_length', label: 'Max length', control: 'number' }],
10432
+ };
10433
+ function getMetaFields(field) {
10434
+ if (!field)
10435
+ return [];
10436
+ const extra = field.datatype ? DATATYPE_FIELDS[field.datatype] ?? [] : [];
10437
+ return [...UNIVERSAL_FIELDS, ...extra].filter(def => !def.showWhen || def.showWhen(field));
10438
+ }
10439
+
10440
+ class ColumnDesignPanelComponent {
10441
+ gridStore = inject(EruGridStore);
10442
+ OBJECT_LIST_KEYS = new Set(['options', 'open_status', 'close_status']);
10443
+ field = computed(() => {
10444
+ const name = this.gridStore.selectedDesignColumn();
10445
+ if (!name)
10446
+ return null;
10447
+ return this.gridStore.columns().find(c => c.name === name) ?? null;
10448
+ }, ...(ngDevMode ? [{ debugName: "field" }] : []));
10449
+ isOpen = computed(() => this.field() !== null, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
10450
+ metaFields = computed(() => getMetaFields(this.field()), ...(ngDevMode ? [{ debugName: "metaFields" }] : []));
10451
+ getValue(key) {
10452
+ return this.field()?.[key] ?? null;
10453
+ }
10454
+ listText(key) {
10455
+ const arr = this.field()?.[key];
10456
+ if (!Array.isArray(arr))
10457
+ return '';
10458
+ return arr.map(it => (typeof it === 'string' ? it : it?.name ?? it?.value ?? '')).join('\n');
10459
+ }
10460
+ patch(key, value) {
10461
+ const name = this.gridStore.selectedDesignColumn();
10462
+ if (!name)
10463
+ return;
10464
+ this.gridStore.updateColumnMeta(name, { [key]: value });
10465
+ }
10466
+ onText(key, value) {
10467
+ this.patch(key, value);
10468
+ }
10469
+ onNumber(key, value) {
10470
+ this.patch(key, value === '' || value === null ? null : Number(value));
10471
+ }
10472
+ onSelect(key, value) {
10473
+ this.patch(key, value);
10474
+ }
10475
+ onCheckbox(key, checked) {
10476
+ this.patch(key, checked);
10477
+ }
10478
+ onList(key, text) {
10479
+ const lines = text.split('\n').map(s => s.trim()).filter(Boolean);
10480
+ const value = this.OBJECT_LIST_KEYS.has(key) ? lines.map(name => ({ name, value: name })) : lines;
10481
+ this.patch(key, value);
10482
+ }
10483
+ close() {
10484
+ this.gridStore.selectDesignColumn(null);
10485
+ }
10486
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ColumnDesignPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10487
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: ColumnDesignPanelComponent, isStandalone: true, selector: "eru-column-design-panel", ngImport: i0, template: "@if (isOpen()) {\n<div class=\"design-panel-backdrop\" (click)=\"close()\"></div>\n}\n<aside class=\"column-design-panel\" [class.open]=\"isOpen()\">\n @if (field(); as col) {\n <header class=\"design-panel-header\">\n <div class=\"design-panel-title\">\n <mat-icon>tune</mat-icon>\n <span>{{ col.label || col.name }}</span>\n </div>\n <button mat-icon-button (click)=\"close()\" title=\"Close\">\n <mat-icon>close</mat-icon>\n </button>\n </header>\n\n <div class=\"design-panel-body\">\n @for (def of metaFields(); track def.key) {\n <div class=\"design-field\">\n @switch (def.control) {\n\n @case ('text') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <input matInput [ngModel]=\"getValue(def.key)\" (ngModelChange)=\"onText(def.key, $event)\" />\n </mat-form-field>\n }\n\n @case ('number') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <input matInput type=\"number\" [ngModel]=\"getValue(def.key)\" (ngModelChange)=\"onNumber(def.key, $event)\" />\n </mat-form-field>\n }\n\n @case ('select') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <mat-select [ngModel]=\"getValue(def.key)\" (ngModelChange)=\"onSelect(def.key, $event)\">\n @for (opt of def.options; track opt.value) {\n <mat-option [value]=\"opt.value\">{{ opt.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @case ('checkbox') {\n <mat-checkbox [checked]=\"!!getValue(def.key)\" (change)=\"onCheckbox(def.key, $event.checked)\">\n {{ def.label }}\n </mat-checkbox>\n }\n\n @case ('list') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <textarea matInput rows=\"4\" [ngModel]=\"listText(def.key)\"\n (ngModelChange)=\"onList(def.key, $event)\"></textarea>\n </mat-form-field>\n }\n\n }\n </div>\n }\n </div>\n }\n</aside>\n", styles: [".design-panel-backdrop{position:fixed;inset:0;background:#0000002e;z-index:1000}.column-design-panel{position:fixed;top:0;right:0;bottom:0;width:360px;max-width:90vw;background:var(--grid-surface, #fff);box-shadow:-4px 0 16px #00000029;transform:translate(100%);transition:transform .22s ease;z-index:1001;display:flex;flex-direction:column;font-family:var(--grid-font-family, inherit)}.column-design-panel.open{transform:translate(0)}.design-panel-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--grid-border-color, #e0e0e0)}.design-panel-header .design-panel-title{display:flex;align-items:center;gap:8px;font-weight:600;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.design-panel-body{padding:16px;overflow-y:auto;flex:1}.design-panel-body .design-field{margin-bottom:4px}.design-panel-body .design-field .full-width{width:100%}.design-panel-body .design-field mat-checkbox{display:block;margin:8px 0 16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: 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: MatSelectModule }, { kind: "component", type: i2$2.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$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
10488
+ }
10489
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ColumnDesignPanelComponent, decorators: [{
10490
+ type: Component,
10491
+ args: [{ selector: 'eru-column-design-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [
10492
+ CommonModule,
10493
+ FormsModule,
10494
+ MatFormFieldModule,
10495
+ MatInputModule,
10496
+ MatSelectModule,
10497
+ MatCheckboxModule,
10498
+ MatIconModule,
10499
+ MatButtonModule,
10500
+ ], template: "@if (isOpen()) {\n<div class=\"design-panel-backdrop\" (click)=\"close()\"></div>\n}\n<aside class=\"column-design-panel\" [class.open]=\"isOpen()\">\n @if (field(); as col) {\n <header class=\"design-panel-header\">\n <div class=\"design-panel-title\">\n <mat-icon>tune</mat-icon>\n <span>{{ col.label || col.name }}</span>\n </div>\n <button mat-icon-button (click)=\"close()\" title=\"Close\">\n <mat-icon>close</mat-icon>\n </button>\n </header>\n\n <div class=\"design-panel-body\">\n @for (def of metaFields(); track def.key) {\n <div class=\"design-field\">\n @switch (def.control) {\n\n @case ('text') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <input matInput [ngModel]=\"getValue(def.key)\" (ngModelChange)=\"onText(def.key, $event)\" />\n </mat-form-field>\n }\n\n @case ('number') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <input matInput type=\"number\" [ngModel]=\"getValue(def.key)\" (ngModelChange)=\"onNumber(def.key, $event)\" />\n </mat-form-field>\n }\n\n @case ('select') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <mat-select [ngModel]=\"getValue(def.key)\" (ngModelChange)=\"onSelect(def.key, $event)\">\n @for (opt of def.options; track opt.value) {\n <mat-option [value]=\"opt.value\">{{ opt.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @case ('checkbox') {\n <mat-checkbox [checked]=\"!!getValue(def.key)\" (change)=\"onCheckbox(def.key, $event.checked)\">\n {{ def.label }}\n </mat-checkbox>\n }\n\n @case ('list') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>{{ def.label }}</mat-label>\n <textarea matInput rows=\"4\" [ngModel]=\"listText(def.key)\"\n (ngModelChange)=\"onList(def.key, $event)\"></textarea>\n </mat-form-field>\n }\n\n }\n </div>\n }\n </div>\n }\n</aside>\n", styles: [".design-panel-backdrop{position:fixed;inset:0;background:#0000002e;z-index:1000}.column-design-panel{position:fixed;top:0;right:0;bottom:0;width:360px;max-width:90vw;background:var(--grid-surface, #fff);box-shadow:-4px 0 16px #00000029;transform:translate(100%);transition:transform .22s ease;z-index:1001;display:flex;flex-direction:column;font-family:var(--grid-font-family, inherit)}.column-design-panel.open{transform:translate(0)}.design-panel-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--grid-border-color, #e0e0e0)}.design-panel-header .design-panel-title{display:flex;align-items:center;gap:8px;font-weight:600;font-size:15px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.design-panel-body{padding:16px;overflow-y:auto;flex:1}.design-panel-body .design-field{margin-bottom:4px}.design-panel-body .design-field .full-width{width:100%}.design-panel-body .design-field mat-checkbox{display:block;margin:8px 0 16px}\n"] }]
10501
+ }] });
10152
10502
 
10153
10503
  /**
10154
10504
  * Custom virtual scroll strategy optimized for catching every scroll event
@@ -10347,6 +10697,11 @@ class EruGridComponent {
10347
10697
  const config = this.gridStore.configuration();
10348
10698
  return config?.config?.groupBar ?? true;
10349
10699
  }, ...(ngDevMode ? [{ debugName: "showGroupBar" }] : []));
10700
+ // Wrap long header labels onto multiple lines instead of truncating (default: true)
10701
+ wrapHeaders = computed(() => {
10702
+ const config = this.gridStore.configuration();
10703
+ return config?.config?.wrapHeaders ?? true;
10704
+ }, ...(ngDevMode ? [{ debugName: "wrapHeaders" }] : []));
10350
10705
  // Row height configuration
10351
10706
  headerRowHeight = computed(() => {
10352
10707
  const config = this.gridStore.configuration();
@@ -11057,12 +11412,15 @@ class EruGridComponent {
11057
11412
  this.lastLoadedGroupIds.delete(group.id);
11058
11413
  }, 1000);
11059
11414
  }
11060
- shouldShowRequiredToggleRow() {
11415
+ isDesignMode() {
11061
11416
  const config = this.gridStore.configuration();
11062
11417
  return config?.config?.designMode === true && this.mode() === 'table';
11063
11418
  }
11064
- onColumnRequiredChange(columnName, required) {
11065
- this.gridStore.updateColumnRequired(columnName, required);
11419
+ onHeaderDesignClick(event, column) {
11420
+ if (!this.isDesignMode())
11421
+ return;
11422
+ event.stopPropagation();
11423
+ this.gridStore.selectDesignColumn(column.name);
11066
11424
  }
11067
11425
  trackByColumnFn(index, column) {
11068
11426
  return column.name;
@@ -11887,7 +12245,7 @@ class EruGridComponent {
11887
12245
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EruGridComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
11888
12246
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: EruGridComponent, isStandalone: true, selector: "eru-grid", inputs: { gridConfig: "gridConfig", boardCardTemplate: "boardCardTemplate", boardCardHeight: "boardCardHeight" }, outputs: { rowSelect: "rowSelect" }, providers: [EruGridStore, EruGridService,
11889
12247
  ...MATERIAL_PROVIDERS
11890
- ], 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 <!-- 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 [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 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\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\">\n <div class=\"column-header\">\n <span class=\"column-header-title\">{{ group.title }}</span>\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n <cdk-virtual-scroll-viewport [itemSize]=\"boardCardHeight\" class=\"board-column-body\"\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 [style.height.px]=\"boardCardHeight\"\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 <!-- 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=\"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 }\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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 [td]=cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\" [value]=\"row?.['entity_data']?.[column.name] || ''\" [column]=\"column\"\n [mode]=\"mode()\" [isEditable]=\"isEditable()\" [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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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] || ''\"\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: 40px; min-width: 40px; max-width: 40px;\">\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: 40px; min-width: 40px; max-width: 40px;\">\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>\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]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0 && !isRowDimensionHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header)\" 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 [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 <!-- <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 [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 {{column.label}}\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<!-- 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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\n }\n </colgroup>\n</ng-template>\n\n\n<ng-template #tableHeader>\n\n <thead>\n @if(shouldShowRequiredToggleRow()) {\n <tr class=\"required-toggle-row\">\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n Action\n </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\" [style.minWidth.px]=\"column.field_size\" class=\"required-toggle-cell\">\n @if(i === 0) {\n <span class=\"required-label\">required</span>\n }\n <mat-checkbox [checked]=\"column.required || false\"\n (change)=\"onColumnRequiredChange(column.name, $event.checked)\" [title]=\"'Make ' + column.label + ' required'\">\n </mat-checkbox>\n </th>\n }\n @if(shouldShowActionColumn('after')) {\n <th class=\"action-column column-header table-column-header\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n Action\n </th>\n }\n </tr>\n }\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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.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\">{{column.label}}</span>\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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] !== 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]\"\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%;min-height:var(--grid-height, 300px);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}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-height, 300px);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{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))}.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{width:40px;min-width:40px;max-width:40px;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)}.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}.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)}.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;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:flex;flex-direction:row;flex:1;min-height:0;overflow-x:auto;overflow-y:hidden;gap:16px;padding:16px;align-items:stretch}.board-mode-host .board-column{flex:0 0 320px;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-weight:600;border-bottom:1px solid var(--grid-outline, #79757f);flex-shrink:0}.board-mode-host .board-column .column-header .column-header-title{font-size:14px;color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-column .column-header .column-header-count{font-size:12px;color:var(--grid-on-surface-variant, #49454f);background:var(--grid-surface-variant, #e7e0ec);border-radius:10px;padding:2px 8px}.board-mode-host .board-column-body{flex:1;min-height:0;height:0}.board-mode-host .board-card-container{padding:4px 8px;box-sizing:border-box;overflow:hidden}.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"], 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$4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$4.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$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i4$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i6.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i6.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i6.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: i8.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: i8.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
12248
+ ], 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 [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 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\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\">\n <div class=\"column-header\">\n <span class=\"column-header-title\">{{ group.title }}</span>\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n <cdk-virtual-scroll-viewport [itemSize]=\"boardCardHeight\" class=\"board-column-body\"\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 [style.height.px]=\"boardCardHeight\"\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 <!-- 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=\"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 }\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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 [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()\" [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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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: 40px; min-width: 40px; max-width: 40px;\">\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: 40px; min-width: 40px; max-width: 40px;\">\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]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0 && !isRowDimensionHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header)\" 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 [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 <!-- <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 [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 {{column.label}}\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<!-- 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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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 (click)=\"onHeaderDesignClick($event, column)\"\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\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\" title=\"Edit 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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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%;min-height:var(--grid-height, 300px);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{cursor:pointer}.column-header.design-clickable .design-edit-icon{font-size:16px;width:16px;height:16px;margin-left:4px;opacity:.45;vertical-align:middle}.column-header.design-clickable:hover .design-edit-icon{opacity:1}.column-header.design-selected{background-color:var(--grid-primary-light, rgba(63, 81, 181, .12))}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-height, 300px);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{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{width:40px;min-width:40px;max-width:40px;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)}.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}.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)}.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;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:flex;flex-direction:row;flex:1;min-height:0;overflow-x:auto;overflow-y:hidden;gap:16px;padding:16px;align-items:stretch}.board-mode-host .board-column{flex:0 0 320px;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-weight:600;border-bottom:1px solid var(--grid-outline, #79757f);flex-shrink:0}.board-mode-host .board-column .column-header .column-header-title{font-size:14px;color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-column .column-header .column-header-count{font-size:12px;color:var(--grid-on-surface-variant, #49454f);background:var(--grid-surface-variant, #e7e0ec);border-radius:10px;padding:2px 8px}.board-mode-host .board-column-body{flex:1;min-height:0;height:0}.board-mode-host .board-card-container{padding:4px 8px;box-sizing:border-box;overflow:hidden}.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"], 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$4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$4.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$1.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.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 });
11891
12249
  }
11892
12250
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: EruGridComponent, decorators: [{
11893
12251
  type: Component,
@@ -11905,8 +12263,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
11905
12263
  MatButtonModule,
11906
12264
  MatMenuModule,
11907
12265
  ResizeColumnDirective,
11908
- ColumnDragDirective
11909
- ], 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 <!-- 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 [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 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\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\">\n <div class=\"column-header\">\n <span class=\"column-header-title\">{{ group.title }}</span>\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n <cdk-virtual-scroll-viewport [itemSize]=\"boardCardHeight\" class=\"board-column-body\"\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 [style.height.px]=\"boardCardHeight\"\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 <!-- 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=\"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 }\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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 [td]=cell [fieldSize]=\"column.field_size\" [columnDatatype]=\"column.datatype\"\n [columnName]=\"column.name\" [value]=\"row?.['entity_data']?.[column.name] || ''\" [column]=\"column\"\n [mode]=\"mode()\" [isEditable]=\"isEditable()\" [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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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] || ''\"\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: 40px; min-width: 40px; max-width: 40px;\">\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: 40px; min-width: 40px; max-width: 40px;\">\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>\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]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0 && !isRowDimensionHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header)\" 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 [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 <!-- <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 [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 {{column.label}}\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<!-- 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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\n }\n </colgroup>\n</ng-template>\n\n\n<ng-template #tableHeader>\n\n <thead>\n @if(shouldShowRequiredToggleRow()) {\n <tr class=\"required-toggle-row\">\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n Action\n </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\" [style.minWidth.px]=\"column.field_size\" class=\"required-toggle-cell\">\n @if(i === 0) {\n <span class=\"required-label\">required</span>\n }\n <mat-checkbox [checked]=\"column.required || false\"\n (change)=\"onColumnRequiredChange(column.name, $event.checked)\" [title]=\"'Make ' + column.label + ' required'\">\n </mat-checkbox>\n </th>\n }\n @if(shouldShowActionColumn('after')) {\n <th class=\"action-column column-header table-column-header\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">\n Action\n </th>\n }\n </tr>\n }\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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.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\">{{column.label}}</span>\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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] !== 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]\"\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%;min-height:var(--grid-height, 300px);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}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-height, 300px);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{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))}.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{width:40px;min-width:40px;max-width:40px;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)}.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}.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)}.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;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:flex;flex-direction:row;flex:1;min-height:0;overflow-x:auto;overflow-y:hidden;gap:16px;padding:16px;align-items:stretch}.board-mode-host .board-column{flex:0 0 320px;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-weight:600;border-bottom:1px solid var(--grid-outline, #79757f);flex-shrink:0}.board-mode-host .board-column .column-header .column-header-title{font-size:14px;color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-column .column-header .column-header-count{font-size:12px;color:var(--grid-on-surface-variant, #49454f);background:var(--grid-surface-variant, #e7e0ec);border-radius:10px;padding:2px 8px}.board-mode-host .board-column-body{flex:1;min-height:0;height:0}.board-mode-host .board-card-container{padding:4px 8px;box-sizing:border-box;overflow:hidden}.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"] }]
12266
+ ColumnDragDirective,
12267
+ ColumnDesignPanelComponent
12268
+ ], 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 [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 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\">\n @for (group of groups(); track group.id) {\n <div class=\"board-column\">\n <div class=\"column-header\">\n <span class=\"column-header-title\">{{ group.title }}</span>\n <span class=\"column-header-count\">{{ group.currentLoadedRows || 0 }} of {{ group.totalRowCount || 0 }}</span>\n </div>\n <cdk-virtual-scroll-viewport [itemSize]=\"boardCardHeight\" class=\"board-column-body\"\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 [style.height.px]=\"boardCardHeight\"\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 <!-- 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=\"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 }\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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 [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()\" [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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px; text-align: center; cursor: pointer;\">\n <mat-icon (click)=\"onActionClick($event, row)\">more_horiz</mat-icon>\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: 40px; min-width: 40px; max-width: 40px;\">\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: 40px; min-width: 40px; max-width: 40px;\">\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]=\"gridStore.isFeatureEnabled('columnResizable') && header.level === 0 && !isRowDimensionHeader(header)\"\n [columnConfig]=\"getFieldForPivotHeader(header)\" 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 [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 <!-- <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 [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 {{column.label}}\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<!-- 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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\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 style=\"width: 60px; min-width: 60px; max-width: 60px;\">\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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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 (click)=\"onHeaderDesignClick($event, column)\"\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\">{{column.label}}</span>\n @if(isDesignMode()) {\n <mat-icon class=\"design-edit-icon\" title=\"Edit 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\"\n style=\"width: 40px; min-width: 40px; max-width: 40px;\">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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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: 40px; min-width: 40px; max-width: 40px;\"></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%;min-height:var(--grid-height, 300px);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{cursor:pointer}.column-header.design-clickable .design-edit-icon{font-size:16px;width:16px;height:16px;margin-left:4px;opacity:.45;vertical-align:middle}.column-header.design-clickable:hover .design-edit-icon{opacity:1}.column-header.design-selected{background-color:var(--grid-primary-light, rgba(63, 81, 181, .12))}.incremental-row-container{width:100%;height:100%;min-height:var(--grid-height, 300px);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{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{width:40px;min-width:40px;max-width:40px;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)}.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}.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)}.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;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:flex;flex-direction:row;flex:1;min-height:0;overflow-x:auto;overflow-y:hidden;gap:16px;padding:16px;align-items:stretch}.board-mode-host .board-column{flex:0 0 320px;display:flex;flex-direction:column;background:var(--grid-surface-container, #f3edf7);border-radius:12px;min-height:0;overflow:hidden}.board-mode-host .board-column .column-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;font-weight:600;border-bottom:1px solid var(--grid-outline, #79757f);flex-shrink:0}.board-mode-host .board-column .column-header .column-header-title{font-size:14px;color:var(--grid-on-surface, #1d1b20)}.board-mode-host .board-column .column-header .column-header-count{font-size:12px;color:var(--grid-on-surface-variant, #49454f);background:var(--grid-surface-variant, #e7e0ec);border-radius:10px;padding:2px 8px}.board-mode-host .board-column-body{flex:1;min-height:0;height:0}.board-mode-host .board-card-container{padding:4px 8px;box-sizing:border-box;overflow:hidden}.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"] }]
11910
12269
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { allViewports: [{
11911
12270
  type: ViewChildren,
11912
12271
  args: [CdkVirtualScrollViewport]
@@ -11994,7 +12353,7 @@ class ThemeToggleComponent {
11994
12353
  </button>
11995
12354
  }
11996
12355
  </mat-menu>
11997
- `, isInline: true, styles: [".theme-toggle-button{color:var(--grid-on-surface)}.theme-toggle-button:hover{background-color:var(--grid-surface-variant)}.active{background-color:var(--grid-primary-light);color:var(--grid-primary-color)}.check-icon{margin-left:auto;color:var(--grid-primary-color)}mat-menu-item{display:flex;align-items:center;gap:8px}\n"], dependencies: [{ 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$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i8.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: i8.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
12356
+ `, isInline: true, styles: [".theme-toggle-button{color:var(--grid-on-surface)}.theme-toggle-button:hover{background-color:var(--grid-surface-variant)}.active{background-color:var(--grid-primary-light);color:var(--grid-primary-color)}.check-icon{margin-left:auto;color:var(--grid-primary-color)}mat-menu-item{display:flex;align-items:center;gap:8px}\n"], dependencies: [{ 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$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11998
12357
  }
11999
12358
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ThemeToggleComponent, decorators: [{
12000
12359
  type: Component,
@@ -12038,5 +12397,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
12038
12397
  * Generated bundle index. Do not edit.
12039
12398
  */
12040
12399
 
12041
- export { AttachmentComponent, CheckboxComponent, ColumnConstraintsService, CurrencyComponent, CustomVirtualScrollStrategy, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, NumberComponent, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent };
12400
+ export { AttachmentComponent, CheckboxComponent, ColumnConstraintsService, CurrencyComponent, CustomVirtualScrollStrategy, DATA_TYPES, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, NumberComponent, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent };
12042
12401
  //# sourceMappingURL=eru-grid.mjs.map