@praxisui/list 10.0.0-rc.37 → 10.0.0-rc.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/component-registry.json +2 -2
- package/fesm2022/praxisui-list.mjs +719 -41
- package/package.json +6 -6
- package/types/praxisui-list.d.ts +43 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, Input, ChangeDetectionStrategy, Component, LOCALE_ID, EventEmitter, output, CSP_NONCE, ElementRef, Renderer2, DestroyRef, ChangeDetectorRef, effect, Injector, isDevMode, booleanAttribute, Output, signal, Optional, SkipSelf, Inject,
|
|
2
|
+
import { inject, Injectable, Input, ChangeDetectionStrategy, Component, LOCALE_ID, EventEmitter, output, CSP_NONCE, ElementRef, Renderer2, DestroyRef, ChangeDetectorRef, effect, Injector, isDevMode, booleanAttribute, ViewChild, Output, signal, Optional, SkipSelf, Inject, ENVIRONMENT_INITIALIZER, computed } from '@angular/core';
|
|
3
3
|
import { ActivatedRoute } from '@angular/router';
|
|
4
4
|
import * as i1 from '@angular/common';
|
|
5
5
|
import { formatDate, CommonModule } from '@angular/common';
|
|
@@ -11,7 +11,7 @@ import * as i4$1 from '@angular/material/radio';
|
|
|
11
11
|
import { MatRadioModule } from '@angular/material/radio';
|
|
12
12
|
import * as i4 from '@angular/material/icon';
|
|
13
13
|
import { MatIconModule } from '@angular/material/icon';
|
|
14
|
-
import { resolveValuePresentation, LoggerService, GenericCrudService, deepMerge, validateGlobalActionRefs, providePraxisI18n, PraxisIconDirective, ASYNC_CONFIG_STORAGE, ComponentKeyService, PraxisJsonLogicService, PraxisI18nService, PraxisCollectionExportService, GlobalActionService, GLOBAL_DIALOG_SERVICE, ResourceRecordOpenError, ResourceRecordOpenService, assertPraxisCollectionExportArtifact, toTitleCase,
|
|
14
|
+
import { resolveValuePresentation, LoggerService, GenericCrudService, deepMerge, validateGlobalActionRefs, providePraxisI18n, PraxisIconDirective, ASYNC_CONFIG_STORAGE, ComponentKeyService, PraxisJsonLogicService, PraxisI18nService, PraxisCollectionExportService, GlobalActionService, GLOBAL_DIALOG_SERVICE, normalizePraxisDataQueryContext, ResourceRecordOpenError, ResourceRecordOpenService, assertPraxisCollectionExportArtifact, toTitleCase, ResourceQuickConnectComponent, ResourceDiscoveryService, PraxisIconButtonComponent, EmptyStateCardComponent, IconPickerService, SURFACE_OPEN_I18N_NAMESPACE, GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, getGlobalActionUiSchema, SurfaceOpenActionEditorComponent, PRAXIS_I18N_CONFIG, providePraxisI18nConfig, SURFACE_OPEN_I18N_CONFIG, ComponentMetadataRegistry, API_URL, LocalStorageAsyncAdapter, LocalStorageConfigService } from '@praxisui/core';
|
|
15
15
|
import * as i2 from '@angular/material/chips';
|
|
16
16
|
import { MatChipsModule } from '@angular/material/chips';
|
|
17
17
|
import { MatDividerModule } from '@angular/material/divider';
|
|
@@ -5740,7 +5740,20 @@ function inferTemplatingFromSchema(cfg, fieldNames) {
|
|
|
5740
5740
|
if (!needsPrimary)
|
|
5741
5741
|
return cfg; // respect user config
|
|
5742
5742
|
const pickBy = (preds, accept = () => true) => names.find((n) => preds.some((p) => p.test(String(n))) && accept(n)) || undefined;
|
|
5743
|
-
const primaryName = pickBy([
|
|
5743
|
+
const primaryName = pickBy([
|
|
5744
|
+
/nomeCompleto/i,
|
|
5745
|
+
/fullName/i,
|
|
5746
|
+
/^nome$/i,
|
|
5747
|
+
/^name$/i,
|
|
5748
|
+
/^nome[A-Z]/,
|
|
5749
|
+
/^title$/i,
|
|
5750
|
+
/^titulo$/i,
|
|
5751
|
+
/title/i,
|
|
5752
|
+
/titulo/i,
|
|
5753
|
+
/label/i,
|
|
5754
|
+
]) ||
|
|
5755
|
+
names.find(isReadableBusinessField) ||
|
|
5756
|
+
names[0];
|
|
5744
5757
|
const avatarName = pickBy([
|
|
5745
5758
|
/avatar/i,
|
|
5746
5759
|
/foto/i,
|
|
@@ -5753,10 +5766,10 @@ function inferTemplatingFromSchema(cfg, fieldNames) {
|
|
|
5753
5766
|
const emailName = pickBy([/email/i, /e-mail/i]);
|
|
5754
5767
|
const phoneName = pickBy([/telefone/i, /phone/i, /celular/i, /mobile/i, /whats/i]);
|
|
5755
5768
|
const cpfName = pickBy([/^cpf$/i, /documento/i, /document/i, /taxId/i]);
|
|
5756
|
-
const roleName = pickBy([/cargoNome/i, /roleName/i, /funcaoNome/i, /funçãoNome/i, /positionName/i]) ||
|
|
5757
|
-
pickBy([/cargo/i, /role/i, /funcao/i, /função/i, /position/i], isReadableBusinessField);
|
|
5758
|
-
const departmentName = pickBy([/departamentoNome/i, /departmentName/i, /areaNome/i, /setorNome/i, /teamName/i]) ||
|
|
5759
|
-
pickBy([/departamento/i, /department/i, /area/i, /setor/i, /team/i], isReadableBusinessField);
|
|
5769
|
+
const roleName = pickBy([/cargoNome/i, /roleName/i, /funcaoNome/i, /funçãoNome/i, /positionName/i], (n) => n !== primaryName) ||
|
|
5770
|
+
pickBy([/cargo/i, /role/i, /funcao/i, /função/i, /position/i], (n) => n !== primaryName && isReadableBusinessField(n));
|
|
5771
|
+
const departmentName = pickBy([/departamentoNome/i, /departmentName/i, /areaNome/i, /setorNome/i, /teamName/i], (n) => n !== primaryName) ||
|
|
5772
|
+
pickBy([/departamento/i, /department/i, /area/i, /setor/i, /team/i], (n) => n !== primaryName && isReadableBusinessField(n));
|
|
5760
5773
|
const descriptionName = names.find((n) => n !== primaryName && /(desc|descricao|descrição|resumo|summary)/i.test(n));
|
|
5761
5774
|
const secondaryFields = [phoneName, emailName].filter(Boolean);
|
|
5762
5775
|
const fallbackSecondaryFields = [cpfName, emailName].filter(Boolean);
|
|
@@ -5824,6 +5837,22 @@ function inferTemplatingFromSchema(cfg, fieldNames) {
|
|
|
5824
5837
|
false: 'warn',
|
|
5825
5838
|
};
|
|
5826
5839
|
}
|
|
5840
|
+
const usesIdentityRowSlot = Array.isArray(draft.layout?.rowLayout?.columns) &&
|
|
5841
|
+
draft.layout.rowLayout.columns.some((col) => col?.slot === 'identity');
|
|
5842
|
+
if (usesIdentityRowSlot && !t.identity && t.primary) {
|
|
5843
|
+
t.identity = t.secondary
|
|
5844
|
+
? {
|
|
5845
|
+
type: 'compose',
|
|
5846
|
+
props: {
|
|
5847
|
+
compose: {
|
|
5848
|
+
direction: 'column',
|
|
5849
|
+
gap: '2px',
|
|
5850
|
+
items: [t.primary, t.secondary],
|
|
5851
|
+
},
|
|
5852
|
+
},
|
|
5853
|
+
}
|
|
5854
|
+
: t.primary;
|
|
5855
|
+
}
|
|
5827
5856
|
draft.templating = t;
|
|
5828
5857
|
});
|
|
5829
5858
|
return newCfg;
|
|
@@ -6004,16 +6033,116 @@ function shouldInferTemplatingFromSchema(config, schemaFieldNames) {
|
|
|
6004
6033
|
}
|
|
6005
6034
|
function hasUngroundedTemplatingSlot(config, schemaFieldNames) {
|
|
6006
6035
|
const slots = config.templating || {};
|
|
6007
|
-
return
|
|
6036
|
+
return ROW_LAYOUT_TEMPLATE_SLOTS.some((slot) => shouldDropTemplatingSlot(slots[slot], schemaFieldNames, slot));
|
|
6008
6037
|
}
|
|
6009
6038
|
function removeUngroundedTemplatingSlots(config, schemaFieldNames) {
|
|
6010
6039
|
const templating = { ...(config.templating || {}) };
|
|
6011
|
-
|
|
6040
|
+
const droppedSlots = new Set();
|
|
6041
|
+
for (const slot of ROW_LAYOUT_TEMPLATE_SLOTS) {
|
|
6012
6042
|
if (shouldDropTemplatingSlot(templating[slot], schemaFieldNames, slot)) {
|
|
6013
6043
|
delete templating[slot];
|
|
6044
|
+
droppedSlots.add(slot);
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
if (droppedSlots.has('trailing') || droppedSlots.has('meta') || droppedSlots.has('leading')) {
|
|
6048
|
+
const hasRemainingChipSlot = ROW_LAYOUT_TEMPLATE_SLOTS.some((slot) => templating[slot]?.type === 'chip');
|
|
6049
|
+
if (!hasRemainingChipSlot) {
|
|
6050
|
+
delete templating['chipColorMap'];
|
|
6051
|
+
delete templating['chipLabelMap'];
|
|
6052
|
+
}
|
|
6053
|
+
const hasRemainingIconFieldSlot = ROW_LAYOUT_TEMPLATE_SLOTS.some((slot) => templating[slot]?.type === 'icon' &&
|
|
6054
|
+
templateFieldReferences(templating[slot]).length > 0);
|
|
6055
|
+
if (!hasRemainingIconFieldSlot) {
|
|
6056
|
+
delete templating['iconColorMap'];
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
const schemaFields = new Set(schemaFieldNames);
|
|
6060
|
+
let nextUi = config.ui;
|
|
6061
|
+
if (nextUi) {
|
|
6062
|
+
let uiMutated = false;
|
|
6063
|
+
const clonedUi = { ...nextUi };
|
|
6064
|
+
if (typeof clonedUi.searchField === 'string' &&
|
|
6065
|
+
clonedUi.searchField.trim().length > 0 &&
|
|
6066
|
+
!schemaFields.has(clonedUi.searchField.trim())) {
|
|
6067
|
+
delete clonedUi.searchField;
|
|
6068
|
+
uiMutated = true;
|
|
6069
|
+
}
|
|
6070
|
+
if (Array.isArray(clonedUi.sortOptions)) {
|
|
6071
|
+
const filteredSortOptions = clonedUi.sortOptions.filter((opt) => {
|
|
6072
|
+
const rawField = String(typeof opt === 'string' ? opt : (opt?.field ?? opt?.value ?? ''))
|
|
6073
|
+
.split(/[,:]/)[0]
|
|
6074
|
+
.trim();
|
|
6075
|
+
return !rawField || schemaFields.has(rawField);
|
|
6076
|
+
});
|
|
6077
|
+
if (filteredSortOptions.length !== clonedUi.sortOptions.length) {
|
|
6078
|
+
clonedUi.sortOptions = filteredSortOptions;
|
|
6079
|
+
uiMutated = true;
|
|
6080
|
+
}
|
|
6081
|
+
}
|
|
6082
|
+
if (uiMutated) {
|
|
6083
|
+
nextUi = clonedUi;
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
let nextDataSource = config.dataSource;
|
|
6087
|
+
if (Array.isArray(nextDataSource?.sort)) {
|
|
6088
|
+
const filteredSort = nextDataSource.sort.filter((entry) => {
|
|
6089
|
+
const rawField = typeof entry === 'string'
|
|
6090
|
+
? entry.split(/[,:]/)[0].trim()
|
|
6091
|
+
: String(entry?.field ?? '').trim();
|
|
6092
|
+
return !rawField || schemaFields.has(rawField);
|
|
6093
|
+
});
|
|
6094
|
+
if (filteredSort.length !== nextDataSource.sort.length) {
|
|
6095
|
+
const clonedDataSource = { ...nextDataSource };
|
|
6096
|
+
if (filteredSort.length > 0) {
|
|
6097
|
+
clonedDataSource.sort = filteredSort;
|
|
6098
|
+
}
|
|
6099
|
+
else {
|
|
6100
|
+
delete clonedDataSource.sort;
|
|
6101
|
+
}
|
|
6102
|
+
nextDataSource = clonedDataSource;
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
if (Array.isArray(nextDataSource?.query?.sort)) {
|
|
6106
|
+
const currentQuerySort = nextDataSource.query.sort;
|
|
6107
|
+
const filteredQuerySort = currentQuerySort.filter((entry) => {
|
|
6108
|
+
const rawField = typeof entry === 'string'
|
|
6109
|
+
? entry.split(/[,:]/)[0].trim()
|
|
6110
|
+
: String(entry?.field ?? '').trim();
|
|
6111
|
+
return !rawField || schemaFields.has(rawField);
|
|
6112
|
+
});
|
|
6113
|
+
if (filteredQuerySort.length !== currentQuerySort.length) {
|
|
6114
|
+
const clonedQuery = { ...nextDataSource.query };
|
|
6115
|
+
if (filteredQuerySort.length > 0) {
|
|
6116
|
+
clonedQuery['sort'] = filteredQuerySort;
|
|
6117
|
+
}
|
|
6118
|
+
else {
|
|
6119
|
+
delete clonedQuery['sort'];
|
|
6120
|
+
}
|
|
6121
|
+
const clonedDataSource = { ...nextDataSource };
|
|
6122
|
+
if (Object.keys(clonedQuery).length > 0) {
|
|
6123
|
+
clonedDataSource.query = clonedQuery;
|
|
6124
|
+
}
|
|
6125
|
+
else {
|
|
6126
|
+
delete clonedDataSource.query;
|
|
6127
|
+
}
|
|
6128
|
+
nextDataSource = clonedDataSource;
|
|
6014
6129
|
}
|
|
6015
6130
|
}
|
|
6016
|
-
|
|
6131
|
+
let nextSelection = config.selection;
|
|
6132
|
+
if (typeof nextSelection?.compareBy === 'string' &&
|
|
6133
|
+
nextSelection.compareBy.trim().length > 0 &&
|
|
6134
|
+
!schemaFields.has(nextSelection.compareBy.trim())) {
|
|
6135
|
+
const clonedSelection = { ...nextSelection };
|
|
6136
|
+
delete clonedSelection.compareBy;
|
|
6137
|
+
nextSelection = clonedSelection;
|
|
6138
|
+
}
|
|
6139
|
+
return {
|
|
6140
|
+
...config,
|
|
6141
|
+
templating,
|
|
6142
|
+
...(nextUi !== config.ui ? { ui: nextUi } : {}),
|
|
6143
|
+
...(nextDataSource !== config.dataSource ? { dataSource: nextDataSource } : {}),
|
|
6144
|
+
...(nextSelection !== config.selection ? { selection: nextSelection } : {}),
|
|
6145
|
+
};
|
|
6017
6146
|
}
|
|
6018
6147
|
function shouldDropTemplatingSlot(template, schemaFieldNames, slot) {
|
|
6019
6148
|
if (!template)
|
|
@@ -7346,7 +7475,14 @@ const PRAXIS_LIST_EN_US = {
|
|
|
7346
7475
|
collapseDetails: 'Collapse details',
|
|
7347
7476
|
itemDetails: 'Item details',
|
|
7348
7477
|
emptyState: 'No items available',
|
|
7478
|
+
emptyStateDescription: 'There are no items to display right now.',
|
|
7479
|
+
emptyStateFilteredTitle: 'No results found',
|
|
7480
|
+
emptyStateFilteredDescription: 'Review the active filters or adjust the search term.',
|
|
7481
|
+
emptyStateClearSearchAction: 'Clear search',
|
|
7482
|
+
emptyStateConnectResourceTitle: 'Choose the list resource',
|
|
7349
7483
|
emptyStateConnectResource: 'Connect this list to a resource to load items.',
|
|
7484
|
+
emptyStateConnectResourceAction: 'Select resource',
|
|
7485
|
+
emptyStateConfigureAction: 'Configure list',
|
|
7350
7486
|
recordOpenUnavailable: 'Unable to open details for this item.',
|
|
7351
7487
|
'selection.ariaLabel': 'Selectable list',
|
|
7352
7488
|
'selection.selectItem': 'Select item',
|
|
@@ -7739,7 +7875,14 @@ const PRAXIS_LIST_PT_BR = {
|
|
|
7739
7875
|
collapseDetails: 'Recolher detalhes',
|
|
7740
7876
|
itemDetails: 'Detalhes do item',
|
|
7741
7877
|
emptyState: 'Nenhum item disponível',
|
|
7878
|
+
emptyStateDescription: 'Não há itens para exibir neste momento.',
|
|
7879
|
+
emptyStateFilteredTitle: 'Nenhum resultado encontrado',
|
|
7880
|
+
emptyStateFilteredDescription: 'Revise os filtros ou ajuste o termo de busca.',
|
|
7881
|
+
emptyStateClearSearchAction: 'Limpar busca',
|
|
7882
|
+
emptyStateConnectResourceTitle: 'Escolha o recurso da lista',
|
|
7742
7883
|
emptyStateConnectResource: 'Conecte a lista a um recurso para carregar os itens.',
|
|
7884
|
+
emptyStateConnectResourceAction: 'Selecionar recurso',
|
|
7885
|
+
emptyStateConfigureAction: 'Configurar lista',
|
|
7743
7886
|
recordOpenUnavailable: 'Não foi possível abrir os detalhes deste item.',
|
|
7744
7887
|
'selection.ariaLabel': 'Lista selecionável',
|
|
7745
7888
|
'selection.selectItem': 'Selecionar item',
|
|
@@ -9496,6 +9639,8 @@ class PraxisList {
|
|
|
9496
9639
|
lastQuery = {};
|
|
9497
9640
|
lastRuntimeQueryContextSignature = '';
|
|
9498
9641
|
search$ = new Subject();
|
|
9642
|
+
activeSearchTerm = '';
|
|
9643
|
+
searchInputRef;
|
|
9499
9644
|
get layoutLines() {
|
|
9500
9645
|
return this.config?.layout?.lines ?? 2;
|
|
9501
9646
|
}
|
|
@@ -9688,6 +9833,17 @@ class PraxisList {
|
|
|
9688
9833
|
return;
|
|
9689
9834
|
if (this.configPersistenceStrategy === 'input-first')
|
|
9690
9835
|
return;
|
|
9836
|
+
const currentPath = String(this.config?.dataSource?.resourcePath ?? '')
|
|
9837
|
+
.trim()
|
|
9838
|
+
.replace(/^\/+|\/+$/g, '')
|
|
9839
|
+
.toLowerCase();
|
|
9840
|
+
const savedPath = String(saved?.dataSource?.resourcePath ?? '')
|
|
9841
|
+
.trim()
|
|
9842
|
+
.replace(/^\/+|\/+$/g, '')
|
|
9843
|
+
.toLowerCase();
|
|
9844
|
+
if (currentPath.length > 0 && savedPath.length > 0 && currentPath !== savedPath) {
|
|
9845
|
+
return;
|
|
9846
|
+
}
|
|
9691
9847
|
const currentId = this.config?.id;
|
|
9692
9848
|
const persisted = currentId
|
|
9693
9849
|
? { ...saved, id: currentId }
|
|
@@ -9728,9 +9884,17 @@ class PraxisList {
|
|
|
9728
9884
|
const field = this.config?.ui?.searchField;
|
|
9729
9885
|
if (!field)
|
|
9730
9886
|
return;
|
|
9731
|
-
const
|
|
9887
|
+
const normalizedTerm = String(term ?? '').trim();
|
|
9888
|
+
const q = { ...(this.lastQuery || {}) };
|
|
9889
|
+
if (normalizedTerm) {
|
|
9890
|
+
q[field] = term;
|
|
9891
|
+
}
|
|
9892
|
+
else {
|
|
9893
|
+
delete q[field];
|
|
9894
|
+
}
|
|
9732
9895
|
this.lastQuery = q;
|
|
9733
9896
|
this.data.setQuery(q);
|
|
9897
|
+
this.cdr.markForCheck();
|
|
9734
9898
|
});
|
|
9735
9899
|
}
|
|
9736
9900
|
async persistConfig(key, config) {
|
|
@@ -10722,6 +10886,81 @@ class PraxisList {
|
|
|
10722
10886
|
const label = this.accessibleItemLabel(item);
|
|
10723
10887
|
return `${label} - ${this.t('itemDetails', 'Detalhes do item').toLowerCase()}`;
|
|
10724
10888
|
}
|
|
10889
|
+
hasCustomEmptyStateTemplate() {
|
|
10890
|
+
return Boolean(this.evalSlot('emptyState', {}));
|
|
10891
|
+
}
|
|
10892
|
+
hasActiveEmptyStateFilters() {
|
|
10893
|
+
if (this.isResourceConnectionMissing())
|
|
10894
|
+
return false;
|
|
10895
|
+
if (this.activeSearchTerm.trim().length > 0)
|
|
10896
|
+
return true;
|
|
10897
|
+
const normalized = normalizePraxisDataQueryContext(this.runtimeQueryContext);
|
|
10898
|
+
const contextFilters = normalized?.filters || {};
|
|
10899
|
+
return Object.values(contextFilters).some((val) => val !== undefined &&
|
|
10900
|
+
val !== null &&
|
|
10901
|
+
String(val).trim().length > 0);
|
|
10902
|
+
}
|
|
10903
|
+
emptyStateIcon() {
|
|
10904
|
+
if (this.isResourceConnectionMissing()) {
|
|
10905
|
+
return 'link';
|
|
10906
|
+
}
|
|
10907
|
+
if (this.hasActiveEmptyStateFilters()) {
|
|
10908
|
+
return 'search_off';
|
|
10909
|
+
}
|
|
10910
|
+
return 'inbox';
|
|
10911
|
+
}
|
|
10912
|
+
emptyStateTitle() {
|
|
10913
|
+
if (this.isResourceConnectionMissing()) {
|
|
10914
|
+
return this.t('emptyStateConnectResourceTitle', 'Escolha o recurso da lista');
|
|
10915
|
+
}
|
|
10916
|
+
if (this.hasActiveEmptyStateFilters()) {
|
|
10917
|
+
return this.t('emptyStateFilteredTitle', 'Nenhum resultado encontrado');
|
|
10918
|
+
}
|
|
10919
|
+
return this.emptyStateLabel();
|
|
10920
|
+
}
|
|
10921
|
+
emptyStateDescription() {
|
|
10922
|
+
if (this.isResourceConnectionMissing()) {
|
|
10923
|
+
return this.emptyStateLabel();
|
|
10924
|
+
}
|
|
10925
|
+
if (this.hasActiveEmptyStateFilters()) {
|
|
10926
|
+
return this.t('emptyStateFilteredDescription', 'Revise os filtros ou ajuste o termo de busca.');
|
|
10927
|
+
}
|
|
10928
|
+
return this.t('emptyStateDescription', 'Não há itens para exibir neste momento.');
|
|
10929
|
+
}
|
|
10930
|
+
emptyStatePrimaryAction() {
|
|
10931
|
+
if (!this.isResourceConnectionMissing() || !this.enableCustomization) {
|
|
10932
|
+
return undefined;
|
|
10933
|
+
}
|
|
10934
|
+
return {
|
|
10935
|
+
label: this.t('emptyStateConnectResourceAction', 'Selecionar recurso'),
|
|
10936
|
+
icon: 'bolt',
|
|
10937
|
+
action: () => this.openQuickConnect(),
|
|
10938
|
+
};
|
|
10939
|
+
}
|
|
10940
|
+
emptyStateSecondaryActions() {
|
|
10941
|
+
if (this.isResourceConnectionMissing()) {
|
|
10942
|
+
if (!this.enableCustomization) {
|
|
10943
|
+
return [];
|
|
10944
|
+
}
|
|
10945
|
+
return [
|
|
10946
|
+
{
|
|
10947
|
+
label: this.t('emptyStateConfigureAction', 'Configurar lista'),
|
|
10948
|
+
icon: 'tune',
|
|
10949
|
+
action: () => this.openConfigEditor(),
|
|
10950
|
+
},
|
|
10951
|
+
];
|
|
10952
|
+
}
|
|
10953
|
+
if (this.activeSearchTerm.trim().length > 0) {
|
|
10954
|
+
return [
|
|
10955
|
+
{
|
|
10956
|
+
label: this.t('emptyStateClearSearchAction', 'Limpar busca'),
|
|
10957
|
+
icon: 'filter_alt_off',
|
|
10958
|
+
action: () => this.clearSearch(),
|
|
10959
|
+
},
|
|
10960
|
+
];
|
|
10961
|
+
}
|
|
10962
|
+
return [];
|
|
10963
|
+
}
|
|
10725
10964
|
emptyStateLabel() {
|
|
10726
10965
|
if (this.isResourceConnectionMissing()) {
|
|
10727
10966
|
return this.t('emptyStateConnectResource', 'Conecte a lista a um recurso para carregar os itens.');
|
|
@@ -11306,6 +11545,58 @@ class PraxisList {
|
|
|
11306
11545
|
return value;
|
|
11307
11546
|
}
|
|
11308
11547
|
}
|
|
11548
|
+
openQuickConnect() {
|
|
11549
|
+
if (!this.enableCustomization)
|
|
11550
|
+
return;
|
|
11551
|
+
const key = this.storageKey();
|
|
11552
|
+
const currentResourcePath = String(this.config?.dataSource?.resourcePath || '').trim();
|
|
11553
|
+
const ref = this.settings.open({
|
|
11554
|
+
id: `praxis-list:quick-connect:${key || this.listId || 'default'}`,
|
|
11555
|
+
owner: this.destroyRef,
|
|
11556
|
+
title: this.t('emptyStateConnectResourceTitle', 'Escolha o recurso da lista'),
|
|
11557
|
+
content: {
|
|
11558
|
+
component: ResourceQuickConnectComponent,
|
|
11559
|
+
inputs: {
|
|
11560
|
+
resourcePath: currentResourcePath || undefined,
|
|
11561
|
+
intent: 'collection',
|
|
11562
|
+
},
|
|
11563
|
+
},
|
|
11564
|
+
});
|
|
11565
|
+
const applyResourceSelection = (val, trigger) => {
|
|
11566
|
+
const nextResourcePath = String(val?.resourcePath || '').trim();
|
|
11567
|
+
if (!nextResourcePath)
|
|
11568
|
+
return;
|
|
11569
|
+
const resourceChanged = Boolean(currentResourcePath) &&
|
|
11570
|
+
currentResourcePath !== nextResourcePath;
|
|
11571
|
+
if (resourceChanged) {
|
|
11572
|
+
this.activeSearchTerm = '';
|
|
11573
|
+
if (this.searchInputRef?.nativeElement) {
|
|
11574
|
+
this.searchInputRef.nativeElement.value = '';
|
|
11575
|
+
}
|
|
11576
|
+
}
|
|
11577
|
+
const { data: _ignoredLocalData, query: existingQuery, sort: existingSort, ...restDataSource } = this.config?.dataSource || {};
|
|
11578
|
+
const nextConfig = {
|
|
11579
|
+
...(this.config || {}),
|
|
11580
|
+
dataSource: {
|
|
11581
|
+
...restDataSource,
|
|
11582
|
+
...(resourceChanged
|
|
11583
|
+
? {}
|
|
11584
|
+
: {
|
|
11585
|
+
...(existingQuery ? { query: existingQuery } : {}),
|
|
11586
|
+
...(existingSort ? { sort: existingSort } : {}),
|
|
11587
|
+
}),
|
|
11588
|
+
resourcePath: nextResourcePath,
|
|
11589
|
+
},
|
|
11590
|
+
};
|
|
11591
|
+
this.applyAuthoringPayload(nextConfig, trigger);
|
|
11592
|
+
};
|
|
11593
|
+
ref.applied$?.pipe(takeUntil(this.destroy$)).subscribe((val) => {
|
|
11594
|
+
applyResourceSelection(val, 'settings-applied');
|
|
11595
|
+
});
|
|
11596
|
+
ref.saved$?.pipe(takeUntil(this.destroy$)).subscribe((val) => {
|
|
11597
|
+
applyResourceSelection(val, 'settings-saved');
|
|
11598
|
+
});
|
|
11599
|
+
}
|
|
11309
11600
|
openConfigEditor() {
|
|
11310
11601
|
void this.openConfigEditorPanel().catch((error) => {
|
|
11311
11602
|
this.logger.error('[PraxisList] Error opening list settings.', this.buildLogOptions({ error }));
|
|
@@ -11680,7 +11971,24 @@ class PraxisList {
|
|
|
11680
11971
|
?.focus({ preventScroll: true });
|
|
11681
11972
|
}
|
|
11682
11973
|
onSearchInput(val) {
|
|
11683
|
-
this.
|
|
11974
|
+
this.activeSearchTerm = val || '';
|
|
11975
|
+
this.search$.next(this.activeSearchTerm);
|
|
11976
|
+
this.cdr.markForCheck();
|
|
11977
|
+
}
|
|
11978
|
+
clearSearch() {
|
|
11979
|
+
this.activeSearchTerm = '';
|
|
11980
|
+
if (this.searchInputRef?.nativeElement) {
|
|
11981
|
+
this.searchInputRef.nativeElement.value = '';
|
|
11982
|
+
}
|
|
11983
|
+
const field = this.config?.ui?.searchField;
|
|
11984
|
+
if (field && this.lastQuery && field in this.lastQuery) {
|
|
11985
|
+
const q = { ...this.lastQuery };
|
|
11986
|
+
delete q[field];
|
|
11987
|
+
this.lastQuery = q;
|
|
11988
|
+
this.data.setQuery(q);
|
|
11989
|
+
}
|
|
11990
|
+
this.search$.next('');
|
|
11991
|
+
this.cdr.markForCheck();
|
|
11684
11992
|
}
|
|
11685
11993
|
isRemoteDataMode() {
|
|
11686
11994
|
const dataSource = this.config?.dataSource;
|
|
@@ -11796,8 +12104,28 @@ class PraxisList {
|
|
|
11796
12104
|
if (plan.diagnostics.some((item) => item.level === 'error')) {
|
|
11797
12105
|
return;
|
|
11798
12106
|
}
|
|
12107
|
+
const prevResourcePath = String(this.appliedRuntimeConfig?.dataSource?.resourcePath || '')
|
|
12108
|
+
.trim()
|
|
12109
|
+
.replace(/^\/+|\/+$/g, '')
|
|
12110
|
+
.replace(/^api\//i, '')
|
|
12111
|
+
.toLowerCase();
|
|
12112
|
+
const nextConfig = normalizeListConfig(plan.canonicalConfig);
|
|
12113
|
+
const nextResourcePath = String(nextConfig?.dataSource?.resourcePath || '')
|
|
12114
|
+
.trim()
|
|
12115
|
+
.replace(/^\/+|\/+$/g, '')
|
|
12116
|
+
.replace(/^api\//i, '')
|
|
12117
|
+
.toLowerCase();
|
|
12118
|
+
if (prevResourcePath.length > 0 &&
|
|
12119
|
+
nextResourcePath.length > 0 &&
|
|
12120
|
+
prevResourcePath !== nextResourcePath) {
|
|
12121
|
+
this.activeSearchTerm = '';
|
|
12122
|
+
if (this.searchInputRef?.nativeElement) {
|
|
12123
|
+
this.searchInputRef.nativeElement.value = '';
|
|
12124
|
+
}
|
|
12125
|
+
this.expandedItemKeys = new Set();
|
|
12126
|
+
}
|
|
11799
12127
|
this.initializeDataStreams();
|
|
11800
|
-
this.config =
|
|
12128
|
+
this.config = nextConfig;
|
|
11801
12129
|
this.appliedRuntimeConfig = this.config;
|
|
11802
12130
|
this.syncPaginatorIntl();
|
|
11803
12131
|
this.syncExpansionState();
|
|
@@ -11822,9 +12150,6 @@ class PraxisList {
|
|
|
11822
12150
|
});
|
|
11823
12151
|
}
|
|
11824
12152
|
}
|
|
11825
|
-
if (plan.runtime?.schemaInference) {
|
|
11826
|
-
this.executeSchemaInferenceForPlan(plan.runtime.schemaInference, plan.persistence?.saveConfig === true);
|
|
11827
|
-
}
|
|
11828
12153
|
if (plan.runtime?.markForCheck) {
|
|
11829
12154
|
this.cdr.markForCheck();
|
|
11830
12155
|
}
|
|
@@ -11835,6 +12160,11 @@ class PraxisList {
|
|
|
11835
12160
|
inputPatch: { config: normalizeListConfig(plan.canonicalConfig) },
|
|
11836
12161
|
});
|
|
11837
12162
|
}
|
|
12163
|
+
if (plan.runtime?.schemaInference) {
|
|
12164
|
+
this.executeSchemaInferenceForPlan(plan.runtime.schemaInference, plan.persistence?.saveConfig === true, trigger === 'settings-applied' ||
|
|
12165
|
+
trigger === 'settings-saved' ||
|
|
12166
|
+
trigger === 'adapter');
|
|
12167
|
+
}
|
|
11838
12168
|
}
|
|
11839
12169
|
storageKey() {
|
|
11840
12170
|
if (this.configPersistenceStrategy === 'volatile') {
|
|
@@ -11861,33 +12191,59 @@ class PraxisList {
|
|
|
11861
12191
|
crud = inject(GenericCrudService, {
|
|
11862
12192
|
optional: true,
|
|
11863
12193
|
});
|
|
11864
|
-
|
|
12194
|
+
resourceDiscovery = inject(ResourceDiscoveryService, {
|
|
12195
|
+
optional: true,
|
|
12196
|
+
});
|
|
12197
|
+
executeSchemaInferenceForPlan(inferencePlan, saveAfterInference = false, publishAuthoringPatch = false) {
|
|
11865
12198
|
const resourcePath = inferencePlan.resourcePath;
|
|
11866
|
-
|
|
12199
|
+
const canDiscover = typeof this.resourceDiscovery?.getResourceSchemaFields === 'function' &&
|
|
12200
|
+
(typeof this.resourceDiscovery.canResolveSchemas !== 'function' ||
|
|
12201
|
+
this.resourceDiscovery.canResolveSchemas());
|
|
12202
|
+
if (!resourcePath || (!this.crud && !canDiscover))
|
|
11867
12203
|
return;
|
|
11868
|
-
|
|
12204
|
+
const inferenceTrigger = saveAfterInference
|
|
12205
|
+
? 'settings-saved'
|
|
12206
|
+
: publishAuthoringPatch
|
|
12207
|
+
? 'settings-applied'
|
|
12208
|
+
: 'schema-inference';
|
|
12209
|
+
const cachedNames = this.schemaFieldsByPath.get(resourcePath);
|
|
12210
|
+
if (this.inferredForPath.has(resourcePath) && cachedNames?.length) {
|
|
12211
|
+
const inferredDocument = inferListAuthoringDocument(inferencePlan.sourceDocument, { schemaFieldNames: cachedNames });
|
|
12212
|
+
if (JSON.stringify(inferredDocument.config) !==
|
|
12213
|
+
JSON.stringify(inferencePlan.sourceDocument.config)) {
|
|
12214
|
+
this.applyAuthoringPayload(inferredDocument, inferenceTrigger);
|
|
12215
|
+
}
|
|
11869
12216
|
return;
|
|
12217
|
+
}
|
|
11870
12218
|
if (this.schemaInferenceInFlight.has(resourcePath))
|
|
11871
12219
|
return;
|
|
11872
12220
|
this.schemaInferenceInFlight.add(resourcePath);
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
.
|
|
12221
|
+
const applyInferredFields = (fields) => {
|
|
12222
|
+
const names = (fields || [])
|
|
12223
|
+
.map((field) => field?.name || field?.field || field?.key)
|
|
12224
|
+
.filter(Boolean);
|
|
12225
|
+
if (!names.length)
|
|
12226
|
+
return false;
|
|
12227
|
+
this.inferredForPath.add(resourcePath);
|
|
12228
|
+
this.schemaFieldsByPath.set(resourcePath, names);
|
|
12229
|
+
const inferredDocument = inferListAuthoringDocument(inferencePlan.sourceDocument, {
|
|
12230
|
+
schemaFieldNames: names,
|
|
12231
|
+
});
|
|
12232
|
+
this.applyAuthoringPayload(inferredDocument, inferenceTrigger);
|
|
12233
|
+
return true;
|
|
12234
|
+
};
|
|
12235
|
+
const tryDiscoveryFallback = () => {
|
|
12236
|
+
if (!canDiscover || !this.resourceDiscovery) {
|
|
12237
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12238
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12239
|
+
return;
|
|
12240
|
+
}
|
|
12241
|
+
this.resourceDiscovery
|
|
12242
|
+
.getResourceSchemaFields(resourcePath)
|
|
11877
12243
|
.pipe(take(1))
|
|
11878
12244
|
.subscribe({
|
|
11879
12245
|
next: (fields) => {
|
|
11880
|
-
|
|
11881
|
-
.map((field) => field?.name || field?.field || field?.key)
|
|
11882
|
-
.filter(Boolean);
|
|
11883
|
-
if (!names.length)
|
|
11884
|
-
return;
|
|
11885
|
-
this.inferredForPath.add(resourcePath);
|
|
11886
|
-
this.schemaFieldsByPath.set(resourcePath, names);
|
|
11887
|
-
const inferredDocument = inferListAuthoringDocument(inferencePlan.sourceDocument, {
|
|
11888
|
-
schemaFieldNames: names,
|
|
11889
|
-
});
|
|
11890
|
-
this.applyAuthoringPayload(inferredDocument, saveAfterInference ? 'settings-saved' : 'schema-inference');
|
|
12246
|
+
applyInferredFields(fields);
|
|
11891
12247
|
},
|
|
11892
12248
|
error: () => {
|
|
11893
12249
|
this.schemaInferenceInFlight.delete(resourcePath);
|
|
@@ -11897,10 +12253,78 @@ class PraxisList {
|
|
|
11897
12253
|
this.schemaInferenceInFlight.delete(resourcePath);
|
|
11898
12254
|
},
|
|
11899
12255
|
});
|
|
12256
|
+
};
|
|
12257
|
+
const tryCrudFallback = () => {
|
|
12258
|
+
if (!this.crud) {
|
|
12259
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12260
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12261
|
+
return;
|
|
12262
|
+
}
|
|
12263
|
+
try {
|
|
12264
|
+
this.crud.configure(resourcePath);
|
|
12265
|
+
this.crud
|
|
12266
|
+
.getSchema()
|
|
12267
|
+
.pipe(take(1))
|
|
12268
|
+
.subscribe({
|
|
12269
|
+
next: (crudFields) => applyInferredFields(crudFields),
|
|
12270
|
+
error: () => {
|
|
12271
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12272
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12273
|
+
},
|
|
12274
|
+
complete: () => {
|
|
12275
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12276
|
+
},
|
|
12277
|
+
});
|
|
12278
|
+
}
|
|
12279
|
+
catch {
|
|
12280
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12281
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12282
|
+
}
|
|
12283
|
+
};
|
|
12284
|
+
const isCatalogResourceKey = !resourcePath.includes('/') && resourcePath.includes('.');
|
|
12285
|
+
if (isCatalogResourceKey && canDiscover && this.resourceDiscovery) {
|
|
12286
|
+
this.resourceDiscovery
|
|
12287
|
+
.getResourceSchemaFields(resourcePath)
|
|
12288
|
+
.pipe(take(1))
|
|
12289
|
+
.subscribe({
|
|
12290
|
+
next: (fields) => {
|
|
12291
|
+
if (!applyInferredFields(fields)) {
|
|
12292
|
+
tryCrudFallback();
|
|
12293
|
+
}
|
|
12294
|
+
else {
|
|
12295
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12296
|
+
}
|
|
12297
|
+
},
|
|
12298
|
+
error: () => {
|
|
12299
|
+
tryCrudFallback();
|
|
12300
|
+
},
|
|
12301
|
+
});
|
|
12302
|
+
return;
|
|
12303
|
+
}
|
|
12304
|
+
try {
|
|
12305
|
+
if (!this.crud) {
|
|
12306
|
+
tryDiscoveryFallback();
|
|
12307
|
+
return;
|
|
12308
|
+
}
|
|
12309
|
+
this.crud.configure(resourcePath);
|
|
12310
|
+
this.crud
|
|
12311
|
+
.getSchema()
|
|
12312
|
+
.pipe(take(1))
|
|
12313
|
+
.subscribe({
|
|
12314
|
+
next: (fields) => {
|
|
12315
|
+
if (!applyInferredFields(fields)) {
|
|
12316
|
+
tryDiscoveryFallback();
|
|
12317
|
+
return;
|
|
12318
|
+
}
|
|
12319
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12320
|
+
},
|
|
12321
|
+
error: () => {
|
|
12322
|
+
tryDiscoveryFallback();
|
|
12323
|
+
},
|
|
12324
|
+
});
|
|
11900
12325
|
}
|
|
11901
12326
|
catch {
|
|
11902
|
-
|
|
11903
|
-
this.schemaFieldsByPath.delete(resourcePath);
|
|
12327
|
+
tryDiscoveryFallback();
|
|
11904
12328
|
}
|
|
11905
12329
|
}
|
|
11906
12330
|
evalSlot(slot, item) {
|
|
@@ -12930,7 +13354,7 @@ class PraxisList {
|
|
|
12930
13354
|
ListDataService,
|
|
12931
13355
|
MatPaginatorIntl,
|
|
12932
13356
|
providePraxisListI18n(),
|
|
12933
|
-
], usesOnChanges: true, ngImport: i0, template: "<div class=\"list-loading-status\" role=\"status\">\n @if (loading$ | async) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"20\" aria-hidden=\"true\"></mat-progress-spinner>\n <span>{{ t('loading', 'Carregando itens\u2026') }}</span>\n }\n</div>\n<div\n class=\"praxis-list-root\"\n tabindex=\"-1\"\n [attr.aria-busy]=\"(loading$ | async) ? 'true' : 'false'\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.data-item-appearance]=\"config?.layout?.itemAppearance || null\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openAiAssistant()\"\n matTooltip=\"Copiloto semantico Praxis\"\n aria-label=\"Abrir copiloto semantico Praxis da lista\"\n data-testid=\"praxis-list-ai-assistant-trigger\"\n >\n <mat-icon [praxisIcon]=\"'auto_awesome'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"\n aiAssistantViewState.state === 'processing' ||\n aiAssistantViewState.state === 'applying'\n \"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-list-ai-assistant\"\n panelTestId=\"praxis-list-ai-assistant-panel\"\n submitTestId=\"praxis-list-ai-assistant-submit\"\n applyTestId=\"praxis-list-ai-assistant-apply\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply()\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n (close)=\"closeAiAssistant()\"\n ></praxis-ai-assistant-shell>\n }\n\n @if (\n config.export?.enabled ||\n (isRemoteDataMode() &&\n (config.ui?.showSort ||\n (config.ui?.showSearch && config.ui?.searchField)))\n ) {\n <div\n class=\"list-collection-toolbar\"\n role=\"group\"\n [attr.aria-label]=\"t('toolbar.label', 'Controles da lista')\"\n >\n @if (\n isRemoteDataMode() && config.ui?.showSearch && config.ui?.searchField\n ) {\n <mat-form-field\n class=\"list-toolbar-search\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{\n config.ui?.searchPlaceholder || t(\"toolbar.search\", \"Buscar\")\n }}</mat-label>\n <mat-icon matPrefix [praxisIcon]=\"'search'\"></mat-icon>\n <input\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n\n <div class=\"list-toolbar-commands\">\n @if (isRemoteDataMode() && config.ui?.showSort) {\n <mat-form-field\n class=\"list-toolbar-sort\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{ t(\"toolbar.sort\", \"Ordenar por\") }}</mat-label>\n @let activeSort = activeSortValue((page$ | async)?.sort);\n <mat-select\n [value]=\"activeSort\"\n (selectionChange)=\"onSortChange($event.value)\"\n >\n @if (activeSort && !hasSortOption(activeSort)) {\n <mat-option [value]=\"activeSort\">{{ activeSort }}</mat-option>\n }\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @if (config.export?.enabled) {\n <button\n mat-stroked-button\n type=\"button\"\n [matMenuTriggerFor]=\"listExportMenu\"\n [attr.aria-label]=\"t('export.button', 'Exportar')\"\n [disabled]=\"exportBusy\"\n [attr.aria-busy]=\"exportBusy\"\n >\n <mat-icon [praxisIcon]=\"'download'\"></mat-icon>\n {{ t(\"export.button\", \"Exportar\") }}\n </button>\n <span class=\"cdk-visually-hidden\" aria-live=\"polite\">\n {{ exportStatusMessage }}\n </span>\n <mat-menu #listExportMenu=\"matMenu\">\n @for (format of listExportFormats(); track format) {\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"onExportAction(format)\"\n >\n <mat-icon [praxisIcon]=\"exportIcon(format)\"></mat-icon>\n {{ format.toUpperCase() }}\n </button>\n }\n </mat-menu>\n }\n </div>\n </div>\n }\n\n <!-- Skeleton while loading -->\n @if (loading$ | async) {\n @if (hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n @if (error$ | async; as remoteError) {\n <div class=\"list-remote-error\" role=\"alert\">\n <mat-icon [praxisIcon]=\"'error_outline'\"></mat-icon>\n <div class=\"list-remote-error__copy\">\n <strong>{{\n t(\"remoteError.title\", \"N\u00E3o foi poss\u00EDvel carregar a lista\")\n }}</strong>\n <span>\n {{\n remoteError.filtered\n ? t(\n \"remoteError.filteredDescription\",\n \"Os filtros permanecem aplicados. Nenhum dado sem filtro foi exibido.\"\n )\n : t(\n \"remoteError.description\",\n \"Verifique a conex\u00E3o e tente novamente.\"\n )\n }}\n </span>\n </div>\n <button mat-stroked-button type=\"button\" (click)=\"retryRemoteData()\">\n {{ t(\"remoteError.retry\", \"Tentar novamente\") }}\n </button>\n </div>\n }\n\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0 && !(error$ | async)) {\n <div\n class=\"section-header\"\n [class.section-header--setup]=\"isResourceConnectionMissing()\"\n >\n @if (emptyStateTemplate(); as empty) {\n @if (\n simpleRichContentNodes(empty, {\n imageAlt: config.templating?.emptyState?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @if (\n simpleRichContentNodes(node, { slot: slot, imageAlt: imageAlt });\n as richNodes\n ) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"[\n slot === 'leading' ? 'leading-icon' : '',\n node?.class || '',\n ]\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n slot === 'leading'\n ? leadingIconStyle(node?.color, node?.style)\n : (node?.style || '' ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img\n [src]=\"node?.value\"\n [alt]=\"node?.imageAlt || imageAlt || ''\"\n />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (\n slot === \"meta\" && config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n }\n </ng-template>\n\n <ng-template #featureContent let-item let-feature=\"feature\">\n @if (featureTemplateNode(item, feature); as featureNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: featureNode,\n slot: 'feature',\n imageAlt: feature?.imageAlt || '',\n }\n \"\n ></ng-container>\n } @else if (featureRichContentNodes(item, feature); as featureNodes) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (feature.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"feature.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"feature.class\" [style.cssText]=\"feature.style\">\n @for (line of featureLabelLines(item, feature.expr); track $index) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, feature.expr, feature.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n >\n @if (clickable) {\n <button\n type=\"button\"\n class=\"list-row-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, index) : null\n \"\n (click)=\"onRowActivate(item, index, sectionKey)\"\n ></button>\n }\n @for (\n column of rowLayoutColumns();\n track rowLayoutTrackColumn($index, column)\n ) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"rowActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #rowActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, index)\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection and row actions share one neutral list shell so every\n interactive affordance remains a sibling keyboard target. -->\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n\n <!-- Unified list surface -->\n <ng-template #readList>\n @if (isVirtualScrollEnabled()) {\n <cdk-virtual-scroll-viewport\n class=\"praxis-list-virtual-viewport\"\n [itemSize]=\"virtualScrollItemSize()\"\n [minBufferPx]=\"virtualScrollMinBufferPx()\"\n [maxBufferPx]=\"virtualScrollMaxBufferPx()\"\n [style.height]=\"virtualScrollViewportHeight()\"\n >\n <mat-list\n class=\"praxis-list-virtual-list\"\n role=\"list\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n <mat-list-item\n *cdkVirtualFor=\"\n let item of virtualScrollItems(sections$ | async, items$ | async);\n let i = index;\n trackBy: trackByVirtualItem\n \"\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n </mat-list>\n </cdk-virtual-scroll-viewport>\n } @else {\n <mat-list\n role=\"list\"\n [class.praxis-list-bounded-viewport]=\"hasBoundedScrollViewport()\"\n [style.max-height]=\"hasBoundedScrollViewport() ? virtualScrollViewportHeight() : null\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n @for (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt:\n config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') +\n iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"sh\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider\n role=\"presentation\"\n aria-hidden=\"true\"\n ></mat-divider>\n }\n }\n }\n </mat-list>\n }\n </ng-template>\n\n <ng-template #listItemBody let-item let-i=\"index\" let-sectionKey=\"sectionKey\">\n <div\n class=\"list-row-shell\"\n [class.list-row-shell--selectable]=\"isSelectionEnabled()\"\n [class.list-row-shell--with-control]=\"shouldShowSelectionControl()\"\n [class.list-row-shell--selected]=\"isItemSelected(item)\"\n [class.list-row-shell--expanded]=\"isExpandable() && isExpanded(item, i)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: sectionKey,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"\n onRowActivate(item, i, sectionKey)\n \"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt:\n config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt ||\n ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(primary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(secondary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (\n item.segmentVariant &&\n item.segmentLabel &&\n item.accountType &&\n item.since\n ) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge\n [variant]=\"item.segmentVariant\"\n [label]=\"item.segmentLabel\"\n ></praxis-executive-badge>\n <span class=\"exec-subcopy\">{{\n item.accountType\n }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\"\n >Desde {{ item.since }}</span\n >\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span\n [innerHTML]=\"secondary(item)?.value\"\n ></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (\n secondary(item)?.type === \"component\"\n ) {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: item, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, { slot: \"meta\" });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(m.color, m.variant)\n \"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"m.value\"\n [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon\n [praxisIcon]=\"mpi2\"\n ></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt:\n config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr.color, tr.variant)\n \"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt ||\n ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (\n item.alertsData !== undefined &&\n item.ownerName\n ) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts\n [alerts]=\"item.alertsData\"\n ></praxis-executive-alerts>\n <praxis-executive-owner\n [name]=\"item.ownerName\"\n ></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, i)\n ? 'expand_less'\n : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon()\n ? isExpanded(item, i)\n : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n action.icon || 'more_horiz'\n \"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, i)\"\n [style.cssText]=\"\n actionIconStyle(action.color)\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"itemActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #itemActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, i)\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n </div>\n </div>\n }\n @if (shouldShowSelectionControl()) {\n <div class=\"list-selection-control\">\n @if (config.selection?.mode === \"multiple\") {\n <mat-checkbox\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, $event.checked)\"\n ></mat-checkbox>\n } @else {\n <mat-radio-button\n [name]=\"selectionControlName()\"\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, true)\"\n ></mat-radio-button>\n }\n </div>\n }\n </div>\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [ngClass]=\"expansionRenderingClasses()\"\n [style]=\"expansionRenderingStyle()\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @case (\"rich-content\") {\n @if (\n expansionRichContentDocument(\n item,\n expansionSection,\n i\n );\n as richExpansionDocument\n ) {\n <praxis-rich-content\n [document]=\"richExpansionDocument\"\n [context]=\"\n expansionRichContentContext(\n item,\n expansionSection,\n i\n )\n \"\n [hostCapabilities]=\"\n expansionRichContentHostCapabilities(\n item,\n expansionSection,\n i\n )\n \"\n rootClassName=\"praxis-list-expansion-rich-content\"\n ></praxis-rich-content>\n }\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"list-item-content card-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n @if (cardDetailSlots(it); as detailSlots) {\n @if (detailSlots.length) {\n <div class=\"card-detail-strip\">\n @for (detail of detailSlots; track detail.slot) {\n <div\n class=\"card-detail\"\n [ngClass]=\"'card-detail--' + detail.slot\"\n >\n <span class=\"card-detail__label\">{{\n detail.label\n }}</span>\n <span class=\"card-detail__value\">\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: detail.node,\n slot: detail.slot,\n imageAlt: rowLayoutImageAlt(detail.slot),\n }\n \"\n ></ng-container>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"tile-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @if (\n simpleRichContentNodes(tr2, {\n imageAlt: tr2.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr2.color, tr2.variant)\n \"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"tr2.value\"\n [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr2\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Remote pagination stays attached to the collection footer. -->\n @if (isRemoteDataMode() && !(error$ | async)) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (config.ui?.showRange === false) {\n <div class=\"list-paginator-total\" aria-live=\"polite\">\n {{ remoteTotalLabel(total) }}\n </div>\n }\n <mat-paginator\n [length]=\"total || 0\"\n [pageIndex]=\"ps.pageNumber || 0\"\n [pageSize]=\"ps.pageSize || config.layout?.pageSize || 10\"\n [pageSizeOptions]=\"listPageSizeOptions()\"\n [selectConfig]=\"paginatorSelectConfig\"\n [showFirstLastButtons]=\"true\"\n [class.hide-range]=\"config.ui?.showRange === false\"\n (page)=\"onPageChange($event)\"\n >\n </mat-paginator>\n }\n }\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{container-type:inline-size;--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var( --md-sys-color-on-primary-container, var(--md-sys-color-on-surface) );--p-list-grad-foreground-muted: color-mix( in srgb, var(--p-list-grad-foreground) 76%, transparent );--p-list-leading-width: 36px;--p-list-trailing-min-width: 140px;--p-list-trailing-max-width: 320px;--p-list-item-gap: 10px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 10px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .875rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 8px;--p-list-action-button-height: 32px;--p-list-tile-minW: 240px;--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-radius: 12px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-gradient-tile .tile-media{background:color-mix(in srgb,var(--md-sys-color-surface) 74%,transparent);border-color:color-mix(in srgb,var(--p-list-foreground) 22%,transparent)}.skin-gradient-tile .tile-media mat-icon,.skin-gradient-tile .tile-meta,.skin-gradient-tile .tile-trailing,.skin-gradient-tile .feature,.skin-gradient-tile .secondary,.skin-gradient-tile .meta{color:var(--p-list-foreground-muted)}.skin-gradient-tile .tile-status,.skin-gradient-tile [data-rich-node-type=badge] .prx-rich-badge{color:var(--md-sys-color-on-secondary-container, var(--p-list-foreground));background:var(--md-sys-color-secondary-container, rgba(255, 255, 255, .72))}.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 6px;--p-list-item-padding-x: 10px;--p-list-item-gap: 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.praxis-list-root.lines-3 .mat-mdc-list-item{min-height:68px}.density-compact{--p-list-tile-gap: 10px;--p-list-tile-padding: 10px;--p-list-tile-minW: 188px}.density-comfortable{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 4px;--p-list-tile-gap: 10px}.item-spacing-default{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{box-sizing:border-box;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),min(34vw,var(--p-list-trailing-max-width)));align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items);position:relative}.list-row-main-action{position:absolute;inset:0;z-index:1;padding:0;border:0;border-radius:inherit;background:transparent;cursor:pointer}.list-row-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{position:relative;z-index:0;min-width:0;height:100%;align-self:stretch;display:flex;align-items:var(--p-list-row-slot-align-items, center);gap:8px}.list-item-content--row-layout :is(.list-row-slot--actions,.list-row-slot--expand,.list-row-slot--trailing){z-index:2}.list-item-content--row-layout .list-row-slot>praxis-rich-content,.list-item-content--row-layout .list-row-slot>praxis-list-metric,.list-item-content--row-layout .list-row-slot>praxis-list-compose,.list-item-content--row-layout .list-row-slot>praxis-list-runtime-component{min-width:0}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary,.list-row-slot--identity{min-width:0}.list-row-slot--identity>praxis-list-compose,.list-row-slot--primary>praxis-list-compose,.list-row-slot--secondary>praxis-list-compose{width:100%}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:nowrap;justify-content:flex-end;gap:8px}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-width:0;min-height:100%}.list-item-leading>praxis-rich-content,.list-row-slot--leading>praxis-rich-content{min-width:0;max-width:100%}:host ::ng-deep .list-item-leading [data-rich-node-type=icon],:host ::ng-deep .list-row-slot--leading [data-rich-node-type=icon]{width:36px;height:36px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 14%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 28%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary, #06b6d4));box-sizing:border-box;flex-shrink:0}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:2px}.list-item-trailing{box-sizing:border-box;min-width:0;width:100%;max-width:var(--p-list-trailing-max-width);display:flex;flex-wrap:nowrap;align-self:center;align-content:center;align-items:center;justify-content:end;gap:8px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-trailing>*{align-self:center}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{width:max-content;justify-self:end;align-self:center;display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap;max-width:100%;min-height:var(--p-list-action-button-height)}.list-item-actions .mat-mdc-button-base{min-height:var(--p-list-action-button-height);height:var(--p-list-action-button-height);display:inline-flex;align-items:center}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item{min-height:40px}.density-comfortable .mat-mdc-list-item{min-height:46px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item{min-height:48px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list mat-list-item:not(:last-child),.praxis-list-root .mat-mdc-list-item:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:var(--p-list-radius, 12px);box-shadow:var(--p-list-shadow, 0 1px 3px rgba(0, 0, 0, .2))}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item:hover .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item:hover .list-item-content{border-color:var(--md-sys-color-primary, #6750a4);box-shadow:var(--md-sys-elevation-level2, 0 2px 6px rgba(0, 0, 0, .25))}.praxis-list-root[data-item-appearance=capsule] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-capsule .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:9999px;box-shadow:var(--p-list-shadow, none)}.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-item-content,.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-row-shell--selectable,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-row-shell--selectable{background:transparent;border:none;box-shadow:none;border-radius:0}.mat-mdc-list-item:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-shell{width:100%;min-width:0}.list-row-shell--selectable{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch;border-radius:calc(var(--p-list-radius) * .75);background:var(--p-list-item-surface);border:var(--p-list-item-border);color:var(--p-list-foreground);overflow:hidden;transition:background .15s ease,box-shadow .15s ease,border-color .15s ease}.list-row-shell--selectable.list-row-shell--with-control{grid-template-columns:minmax(0,1fr) auto}.list-selection-control{position:relative;z-index:2;display:flex;align-items:flex-start;justify-content:center;padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x) var(--p-list-item-padding-y) 0}.list-selection-control mat-radio-button{--mat-radio-selected-icon-color: var(--p-list-foreground);--mat-radio-selected-hover-icon-color: var(--p-list-foreground);--mat-radio-selected-focus-icon-color: var(--p-list-foreground);--mat-radio-selected-pressed-icon-color: var(--p-list-foreground);--mat-radio-checked-ripple-color: var(--p-list-foreground)}.praxis-list-root .mat-mdc-list-item .list-row-shell--selectable .list-item-content{background:transparent;border:0;border-radius:0;box-shadow:none}.mat-mdc-list-item:hover .list-row-shell--selectable{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-row-shell--selectable{background:var(--p-list-item-active-surface)}.list-row-shell--selected{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.skin-elevated .list-row-shell--selectable,.skin-outline .list-row-shell--selectable,.skin-flat .list-row-shell--selectable,.skin-neumorphism .list-row-shell--selectable{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-item-border);box-shadow:var(--p-list-shadow)}.skin-pill-soft .list-row-shell--selectable{border-radius:calc(var(--p-list-radius) * 1.3);background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-border);box-shadow:var(--md-sys-elevation-level1)}.skin-gradient-tile .list-row-shell--selectable{border-radius:var(--p-list-radius);background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));color:var(--p-list-foreground)}.skin-glass .list-row-shell--selectable{border-radius:var(--p-list-radius);background:var(--md-sys-color-surface-container-low);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #5b6f84;--p-list-chip-background: #eef4f8;--p-list-chip-color: #17324d;--p-list-chip-border-color: #d5e2ec;--md-sys-color-on-surface: #17324d;--md-sys-color-on-surface-variant: #5b6f84;--md-sys-color-surface: #ffffff;--md-sys-color-surface-container-low: #f1f5f9;--md-sys-color-surface-container: #e2e8f0;--md-sys-color-surface-container-high: #e2e8f0;--md-sys-color-surface-container-highest: #cbd5e1;--md-sys-color-outline: #94a3b8;--md-sys-color-outline-variant: #d5e2ec;--praxis-icon-btn-fg: #6d7f93;color:var(--p-list-foreground)}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 16px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}:host ::ng-deep .executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}:host ::ng-deep .executive-inline-skin .exec-balance-metric,:host ::ng-deep .executive-inline-skin .exec-limit-metric,:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:0;gap:5px}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__value,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:84px;justify-items:center}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:5px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__below-progress,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon .prx-rich-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{--praxis-icon-btn-fg: #6d7f93;width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb;color:var(--p-list-foreground)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;max-width:100%;min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta>span,.meta praxis-rich-content{min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta .mat-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;line-height:1;vertical-align:middle}.trailing{color:var(--p-list-foreground-muted);margin-left:0;max-width:100%;min-width:0;display:inline-flex;justify-content:flex-end;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trailing praxis-rich-content{min-width:0}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge]{background:transparent;color:inherit}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge{min-height:22px;padding:2px 10px;border-radius:999px;font-size:.72rem;font-weight:600;letter-spacing:.02em;border:1px solid var(--p-list-chip-border-color, transparent);background:var(--p-list-chip-background, var(--md-sys-color-primary-container, #e8def8));color:var(--p-list-chip-color, var(--md-sys-color-on-primary-container, #21005d));line-height:18px}.section-header{display:block;font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.section-header praxis-rich-content{display:block;width:100%}.section-header--setup{margin:8px 12px 12px;padding:14px 16px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:color-mix(in srgb,var(--p-list-surface) 92%,var(--md-sys-color-primary) 8%);color:var(--p-list-foreground);font-weight:500}.praxis-list-root mat-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:var(--p-list-expansion-padding, 14px 16px);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75);color:var(--p-list-foreground)}.praxis-list-root[data-item-appearance=card] .list-row-shell--expanded .list-item-content,.praxis-list-root.item-appearance-card .list-row-shell--expanded .list-item-content{border-bottom-left-radius:0;border-bottom-right-radius:0}.praxis-list-root[data-item-appearance=card] .item-expansion--attached,.praxis-list-root.item-appearance-card .item-expansion--attached{margin:0;border-top:0;border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:var(--p-list-radius, 12px);border-bottom-right-radius:var(--p-list-radius, 12px);background:color-mix(in srgb,var(--md-sys-color-surface-container-low, var(--p-list-surface)) 82%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 65%,transparent)}.skin-glass .item-expansion--attached{backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.item-expansion--detached,.item-expansion--modal{margin-top:var(--p-list-item-stack-gap);background:var(--md-sys-color-surface-container, var(--p-list-surface));box-shadow:var(--md-sys-elevation-level1)}.item-expansion--modal{border-color:var(--md-sys-color-outline);box-shadow:var(--md-sys-elevation-level3)}.item-expansion-grid{display:grid;grid-template-columns:var(--p-list-expansion-columns, repeat(auto-fit, minmax(220px, 1fr)));gap:var(--p-list-expansion-gap, 16px)}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground)}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted)}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px 16px}.expansion-key-value-row{display:grid;gap:2px;padding:6px 10px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-surface-container-highest, rgba(255, 255, 255, .04)) 45%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 45%,transparent)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0}.expansion-key-value-row dt{font-size:.68rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.85rem;font-weight:600;color:var(--p-list-foreground)}.cards-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, max(300px, var(--p-list-tile-minW)))), 1fr)));gap:max(var(--p-list-tile-gap),16px)}.tiles-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, var(--p-list-tile-minW))), 1fr)));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.tile-main-action{display:flex;flex:1;min-width:0;flex-direction:column;gap:10px;color:inherit;cursor:pointer}.tile-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid,.cards-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:max(var(--p-list-tile-padding),16px);display:flex;flex-direction:column;gap:var(--p-list-item-gap);min-height:var(--p-list-card-minH, 220px);position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.density-compact .item-card{min-height:var(--p-list-card-minH, 148px)}.pdx-list-item--primary{--p-list-item-rule-tone: var(--md-sys-color-primary, #06b6d4);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 52%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--success{--p-list-item-rule-tone: var(--p-color-success, #10b981);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 48%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--warning{--p-list-item-rule-tone: var( --p-color-warning, var(--md-sys-color-tertiary, #f59e0b) );border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 54%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 10%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--danger{--p-list-item-rule-tone: var(--md-sys-color-error, #ef4444);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 56%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 11%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--muted{opacity:.78;border-style:dashed!important;background:color-mix(in srgb,var(--md-sys-color-surface-variant) 34%,var(--p-list-surface))!important}.pdx-list-item--neutral{border-color:var(--md-sys-color-outline-variant)!important;background:var(--p-list-surface)!important}.card-main-action{display:block;width:100%;min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.card-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.item-card .list-item-content{display:block;padding:0;min-width:0;overflow:hidden}.item-card .list-item-leading{position:absolute;top:18px;left:18px;min-height:0;z-index:1}.item-card .leading-placeholder{width:36px;height:36px}.item-card .leading-icon.mat-icon,.item-card .list-item-leading>mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent));color:var(--md-sys-color-primary)}.item-card .list-item-text{display:grid;gap:9px;padding-left:50px;width:100%;min-width:0;box-sizing:border-box}.item-card .primary{padding-right:min(50%,160px);font-size:1rem;font-weight:800;letter-spacing:-.01em;line-height:1.18;min-width:0;overflow-wrap:anywhere}.item-card .secondary{color:var(--p-list-foreground-muted);font-weight:600;line-height:1.35;min-width:0;overflow-wrap:anywhere}.item-card .features{display:flex;flex-direction:column;gap:8px;margin-top:2px}.item-card .feature{display:inline-flex;align-items:start;gap:8px;min-width:0;max-width:100%;overflow-wrap:anywhere}.item-card .feature mat-icon{margin-top:1px;color:var(--p-list-foreground-muted);opacity:.86}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width);grid-column:1/-1;align-items:stretch;padding-right:0}.card-detail-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:10px;margin-top:16px}.card-detail{min-width:0;padding:11px 12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 22%,transparent),color-mix(in srgb,var(--p-list-surface) 92%,transparent));box-shadow:inset 0 1px #ffffff14}.card-detail__label{display:block;margin-bottom:3px;color:var(--p-list-foreground-muted);font-size:.68rem;font-weight:700;letter-spacing:.08em;line-height:1.1;text-transform:uppercase}.card-detail__value{display:block;min-width:0;color:var(--p-list-foreground);font-size:.94rem;font-weight:800;line-height:1.2;overflow-wrap:normal;word-break:normal}.card-detail__value,.card-detail__value *{white-space:nowrap}.card-detail--balance .card-detail__value{color:var(--md-sys-color-primary)}.card-detail--limit .card-detail__value{color:var(--md-sys-color-error)}.card-detail--risk .card-detail__value{color:var(--md-sys-color-tertiary, var(--p-list-foreground))}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);margin-top:auto}.status-overlay{position:absolute;top:14px;right:14px;max-width:min(42%,148px);overflow:hidden;pointer-events:none}.status-overlay .mat-mdc-chip{pointer-events:auto;width:100%;min-width:0;max-width:100%}.status-overlay .mdc-evolution-chip__text-label,.status-overlay .mat-mdc-chip-action-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.leading-icon.mat-icon,.list-item-leading>mat-icon,.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon],[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon]{width:36px;height:36px;min-width:36px;line-height:36px;font-size:19px;display:inline-flex;align-items:center;justify-content:center;border-radius:10px;box-sizing:border-box;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 15%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 30%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary));box-shadow:inset 0 1px #ffffff0f}.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon,[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon{font-size:19px;width:19px;height:19px;line-height:19px;color:inherit}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);--mdc-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mat-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mdc-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mat-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mdc-chip-outline-color: var(--p-list-chip-border-color, transparent);--mat-chip-outline-color: var(--p-list-chip-border-color, transparent);font-size:var(--p-list-chip-font-size);font-weight:600;letter-spacing:.02em;border-radius:999px!important;background-color:var(--p-list-chip-background, var(--md-sys-color-surface-container-high))!important;color:var(--p-list-chip-color, var(--md-sys-color-on-surface))!important;border:1px solid var(--p-list-chip-border-color, transparent)!important}:host ::ng-deep .mat-mdc-chip .mdc-evolution-chip__text-label,:host ::ng-deep .mat-mdc-chip .mat-mdc-chip-action-label{color:var(--p-list-chip-color, inherit)!important;font-weight:600;font-size:.72rem;letter-spacing:.02em}.meta .mat-icon{font-size:18px;height:18px;width:18px}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important;color:var(--p-list-chip-color, currentColor)!important}.w-60{width:60%}.w-40{width:40%}.list-collection-toolbar{display:flex;align-items:center;gap:12px;padding:12px;margin-bottom:8px;color:var(--p-list-foreground);background:var(--p-list-surface-low);border:var(--p-list-border);border-radius:calc(var(--p-list-radius) * .75)}.list-toolbar-search{flex:1 1 320px;min-width:220px;max-width:440px}.list-toolbar-commands{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-inline-start:auto}.list-toolbar-commands button{border-radius:8px}.list-toolbar-commands button .mat-icon{margin-right:6px}.list-toolbar-sort{width:200px}.list-remote-error{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;margin:8px 4px 0;padding:16px;color:var(--md-sys-color-on-error-container);background:var(--md-sys-color-error-container);border-radius:calc(var(--p-list-radius) * .75)}.list-remote-error__copy{display:flex;flex-direction:column;gap:4px;min-width:0}.list-remote-error__copy span{color:color-mix(in srgb,var(--md-sys-color-on-error-container) 82%,transparent);line-height:1.45}.list-remote-error button{color:var(--md-sys-color-on-error-container);--mat-button-outlined-label-text-color: var( --md-sys-color-on-error-container );--mat-button-outlined-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent );--mdc-outlined-button-label-text-color: var( --md-sys-color-on-error-container );--mdc-outlined-button-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent )}.mat-mdc-paginator{margin-top:14px;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--p-list-surface-low);color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-container{min-height:40px;padding:4px 8px;gap:6px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select{margin-left:8px;width:92px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-text-field-wrapper{--mdc-outlined-text-field-container-color: color-mix( in srgb, var(--p-list-surface-low) 92%, var(--md-sys-color-on-surface) 8% );--mdc-outlined-text-field-input-text-color: var(--p-list-foreground);min-height:40px;padding-inline:12px 8px;background:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;background-color:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;color:var(--p-list-foreground)!important}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-form-field-infix{min-height:40px;padding-block:8px;width:auto}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-select-trigger{min-height:24px;padding-right:2px;color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-range-label,:host ::ng-deep .mat-mdc-paginator .mat-mdc-select-value-text{font-size:12px;color:var(--p-list-foreground-muted)}.list-paginator-total{margin-top:14px;padding:4px 8px 0;font-size:12px;color:var(--p-list-foreground-muted)}:host ::ng-deep .mat-mdc-paginator.hide-range .mat-mdc-paginator-range-label{display:none}::ng-deep .praxis-list-paginator-select-panel.mat-mdc-select-panel{--mat-select-panel-background-color: var( --md-sys-color-surface-container, var(--mat-sys-surface-container) );background:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;background-color:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 70%,transparent);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, #000) 28%,transparent)}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option{--mat-option-label-text-color: var(--md-sys-color-on-surface, #111827);color:var(--md-sys-color-on-surface, #111827)!important}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled),::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option.mat-mdc-option-active{--mat-option-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-primary, #2f7cff) 14%, transparent );background:color-mix(in srgb,var(--md-sys-color-primary, #2f7cff) 14%,transparent)!important;color:var(--md-sys-color-on-surface, #111827)!important}.muted{color:var(--p-list-foreground-muted)}@container (max-width: 720px){.executive-inline-skin .list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.executive-inline-skin .list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--primary,.executive-inline-skin .list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.executive-inline-skin .list-item-content--row-layout .list-row-slot--meta,.executive-inline-skin .list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.executive-inline-skin .list-selection-control{padding-left:0}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.executive-inline-skin .list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.executive-inline-skin .list-item-trailing .list-item-actions{margin-inline-start:auto}.executive-inline-skin .item-expansion{margin-left:0;margin-right:0}.executive-inline-skin .list-collection-toolbar{flex-direction:column;align-items:stretch}.executive-inline-skin .list-toolbar-search,.executive-inline-skin .list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.executive-inline-skin .list-toolbar-commands{width:100%;margin-inline-start:0}.executive-inline-skin .list-toolbar-sort{flex:1 1 100%}.executive-inline-skin .list-toolbar-commands button{flex:0 0 auto}.executive-inline-skin .list-remote-error{grid-template-columns:auto minmax(0,1fr)}.executive-inline-skin .list-remote-error button{grid-column:1/-1;justify-self:stretch}}@container (max-width: 420px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}@media(max-width:640px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}.list-loading-status{display:flex;align-items:center;gap:8px;padding:12px 0;color:inherit;--mat-progress-spinner-active-indicator-color: currentColor}.list-loading-status:empty{display:none}.praxis-list-virtual-viewport,.praxis-list-bounded-viewport{display:block;width:100%;overflow-y:auto;outline:none;padding-right:4px;box-sizing:border-box;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent) transparent}.praxis-list-virtual-viewport::-webkit-scrollbar,.praxis-list-bounded-viewport::-webkit-scrollbar{width:6px;height:6px}.praxis-list-virtual-viewport::-webkit-scrollbar-track,.praxis-list-bounded-viewport::-webkit-scrollbar-track{background:transparent}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent);border-radius:999px}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb:hover,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--md-sys-color-on-surface-variant, #94a3b8) 72%,transparent)}.praxis-list-virtual-viewport{height:var(--p-list-viewport-height, 400px);contain:strict}.praxis-list-virtual-viewport .praxis-list-virtual-list{padding-top:0;padding-bottom:0}.list-item-menu-trigger{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--md-sys-shape-corner-full, 9999px);color:var(--p-list-foreground-muted, inherit);transition:background-color .15s ease,color .15s ease}.list-item-menu-trigger:hover{background-color:var(--p-list-item-hover-surface, rgba(0, 0, 0, .04));color:var(--p-list-foreground, inherit)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$1.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i2$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i2$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3.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: MatRadioModule }, { kind: "component", type: i4$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i7.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i7.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", 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: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i9.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i11.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4$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: i4$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.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: MatTooltipModule }, { kind: "directive", type: i14.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "label", "variant"] }, { kind: "component", type: ExecutiveAlertsComponent, selector: "praxis-executive-alerts", inputs: ["alerts"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"], outputs: ["nodeAction"] }, { kind: "component", type: PraxisListMetricComponent, selector: "praxis-list-metric", inputs: ["metric"] }, { kind: "component", type: PraxisListComposeComponent, selector: "praxis-list-compose", inputs: ["compose"] }, { kind: "component", type: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i15.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i15.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i15.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13357
|
+
], viewQueries: [{ propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"list-loading-status\" role=\"status\">\n @if (loading$ | async) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"20\" aria-hidden=\"true\"></mat-progress-spinner>\n <span>{{ t('loading', 'Carregando itens\u2026') }}</span>\n }\n</div>\n<div\n class=\"praxis-list-root\"\n tabindex=\"-1\"\n [attr.aria-busy]=\"(loading$ | async) ? 'true' : 'false'\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.data-item-appearance]=\"config?.layout?.itemAppearance || null\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openAiAssistant()\"\n matTooltip=\"Copiloto semantico Praxis\"\n aria-label=\"Abrir copiloto semantico Praxis da lista\"\n data-testid=\"praxis-list-ai-assistant-trigger\"\n >\n <mat-icon [praxisIcon]=\"'auto_awesome'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"\n aiAssistantViewState.state === 'processing' ||\n aiAssistantViewState.state === 'applying'\n \"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-list-ai-assistant\"\n panelTestId=\"praxis-list-ai-assistant-panel\"\n submitTestId=\"praxis-list-ai-assistant-submit\"\n applyTestId=\"praxis-list-ai-assistant-apply\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply()\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n (close)=\"closeAiAssistant()\"\n ></praxis-ai-assistant-shell>\n }\n\n @if (\n config.export?.enabled ||\n (isRemoteDataMode() &&\n (config.ui?.showSort ||\n (config.ui?.showSearch && config.ui?.searchField)))\n ) {\n <div\n class=\"list-collection-toolbar\"\n role=\"group\"\n [attr.aria-label]=\"t('toolbar.label', 'Controles da lista')\"\n >\n @if (\n isRemoteDataMode() && config.ui?.showSearch && config.ui?.searchField\n ) {\n <mat-form-field\n class=\"list-toolbar-search\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{\n config.ui?.searchPlaceholder || t(\"toolbar.search\", \"Buscar\")\n }}</mat-label>\n <mat-icon matPrefix [praxisIcon]=\"'search'\"></mat-icon>\n <input\n #searchInput\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n\n <div class=\"list-toolbar-commands\">\n @if (isRemoteDataMode() && config.ui?.showSort) {\n <mat-form-field\n class=\"list-toolbar-sort\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{ t(\"toolbar.sort\", \"Ordenar por\") }}</mat-label>\n @let activeSort = activeSortValue((page$ | async)?.sort);\n <mat-select\n [value]=\"activeSort\"\n (selectionChange)=\"onSortChange($event.value)\"\n >\n @if (activeSort && !hasSortOption(activeSort)) {\n <mat-option [value]=\"activeSort\">{{ activeSort }}</mat-option>\n }\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @if (config.export?.enabled) {\n <button\n mat-stroked-button\n type=\"button\"\n [matMenuTriggerFor]=\"listExportMenu\"\n [attr.aria-label]=\"t('export.button', 'Exportar')\"\n [disabled]=\"exportBusy\"\n [attr.aria-busy]=\"exportBusy\"\n >\n <mat-icon [praxisIcon]=\"'download'\"></mat-icon>\n {{ t(\"export.button\", \"Exportar\") }}\n </button>\n <span class=\"cdk-visually-hidden\" aria-live=\"polite\">\n {{ exportStatusMessage }}\n </span>\n <mat-menu #listExportMenu=\"matMenu\">\n @for (format of listExportFormats(); track format) {\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"onExportAction(format)\"\n >\n <mat-icon [praxisIcon]=\"exportIcon(format)\"></mat-icon>\n {{ format.toUpperCase() }}\n </button>\n }\n </mat-menu>\n }\n </div>\n </div>\n }\n\n <!-- Skeleton while loading -->\n @if (loading$ | async) {\n @if (hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n @if (error$ | async; as remoteError) {\n <div class=\"list-remote-error\" role=\"alert\">\n <mat-icon [praxisIcon]=\"'error_outline'\"></mat-icon>\n <div class=\"list-remote-error__copy\">\n <strong>{{\n t(\"remoteError.title\", \"N\u00E3o foi poss\u00EDvel carregar a lista\")\n }}</strong>\n <span>\n {{\n remoteError.filtered\n ? t(\n \"remoteError.filteredDescription\",\n \"Os filtros permanecem aplicados. Nenhum dado sem filtro foi exibido.\"\n )\n : t(\n \"remoteError.description\",\n \"Verifique a conex\u00E3o e tente novamente.\"\n )\n }}\n </span>\n </div>\n <button mat-stroked-button type=\"button\" (click)=\"retryRemoteData()\">\n {{ t(\"remoteError.retry\", \"Tentar novamente\") }}\n </button>\n </div>\n }\n\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0 && !(error$ | async)) {\n @if (hasCustomEmptyStateTemplate()) {\n <div\n class=\"section-header\"\n [class.section-header--setup]=\"isResourceConnectionMissing()\"\n >\n @if (emptyStateTemplate(); as empty) {\n @if (\n simpleRichContentNodes(empty, {\n imageAlt: config.templating?.emptyState?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n }\n </div>\n } @else {\n <praxis-empty-state-card\n class=\"section-header\"\n [class.section-header--setup]=\"isResourceConnectionMissing()\"\n [icon]=\"emptyStateIcon()\"\n [title]=\"emptyStateTitle()\"\n [description]=\"emptyStateDescription()\"\n [primaryAction]=\"emptyStatePrimaryAction()\"\n [secondaryActions]=\"emptyStateSecondaryActions()\"\n />\n }\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @if (\n simpleRichContentNodes(node, { slot: slot, imageAlt: imageAlt });\n as richNodes\n ) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"[\n slot === 'leading' ? 'leading-icon' : '',\n node?.class || '',\n ]\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n slot === 'leading'\n ? leadingIconStyle(node?.color, node?.style)\n : (node?.style || '' ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img\n [src]=\"node?.value\"\n [alt]=\"node?.imageAlt || imageAlt || ''\"\n />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (\n slot === \"meta\" && config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n }\n </ng-template>\n\n <ng-template #featureContent let-item let-feature=\"feature\">\n @if (featureTemplateNode(item, feature); as featureNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: featureNode,\n slot: 'feature',\n imageAlt: feature?.imageAlt || '',\n }\n \"\n ></ng-container>\n } @else if (featureRichContentNodes(item, feature); as featureNodes) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (feature.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"feature.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"feature.class\" [style.cssText]=\"feature.style\">\n @for (line of featureLabelLines(item, feature.expr); track $index) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, feature.expr, feature.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n >\n @if (clickable) {\n <button\n type=\"button\"\n class=\"list-row-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, index) : null\n \"\n (click)=\"onRowActivate(item, index, sectionKey)\"\n ></button>\n }\n @for (\n column of rowLayoutColumns();\n track rowLayoutTrackColumn($index, column)\n ) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"rowActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #rowActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, index)\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection and row actions share one neutral list shell so every\n interactive affordance remains a sibling keyboard target. -->\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n\n <!-- Unified list surface -->\n <ng-template #readList>\n @if (isVirtualScrollEnabled()) {\n <cdk-virtual-scroll-viewport\n class=\"praxis-list-virtual-viewport\"\n [itemSize]=\"virtualScrollItemSize()\"\n [minBufferPx]=\"virtualScrollMinBufferPx()\"\n [maxBufferPx]=\"virtualScrollMaxBufferPx()\"\n [style.height]=\"virtualScrollViewportHeight()\"\n >\n <mat-list\n class=\"praxis-list-virtual-list\"\n role=\"list\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n <mat-list-item\n *cdkVirtualFor=\"\n let item of virtualScrollItems(sections$ | async, items$ | async);\n let i = index;\n trackBy: trackByVirtualItem\n \"\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n </mat-list>\n </cdk-virtual-scroll-viewport>\n } @else {\n <mat-list\n role=\"list\"\n [class.praxis-list-bounded-viewport]=\"hasBoundedScrollViewport()\"\n [style.max-height]=\"hasBoundedScrollViewport() ? virtualScrollViewportHeight() : null\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n @for (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt:\n config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') +\n iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"sh\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider\n role=\"presentation\"\n aria-hidden=\"true\"\n ></mat-divider>\n }\n }\n }\n </mat-list>\n }\n </ng-template>\n\n <ng-template #listItemBody let-item let-i=\"index\" let-sectionKey=\"sectionKey\">\n <div\n class=\"list-row-shell\"\n [class.list-row-shell--selectable]=\"isSelectionEnabled()\"\n [class.list-row-shell--with-control]=\"shouldShowSelectionControl()\"\n [class.list-row-shell--selected]=\"isItemSelected(item)\"\n [class.list-row-shell--expanded]=\"isExpandable() && isExpanded(item, i)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: sectionKey,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"\n onRowActivate(item, i, sectionKey)\n \"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt:\n config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt ||\n ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(primary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(secondary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (\n item.segmentVariant &&\n item.segmentLabel &&\n item.accountType &&\n item.since\n ) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge\n [variant]=\"item.segmentVariant\"\n [label]=\"item.segmentLabel\"\n ></praxis-executive-badge>\n <span class=\"exec-subcopy\">{{\n item.accountType\n }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\"\n >Desde {{ item.since }}</span\n >\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span\n [innerHTML]=\"secondary(item)?.value\"\n ></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (\n secondary(item)?.type === \"component\"\n ) {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: item, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, { slot: \"meta\" });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(m.color, m.variant)\n \"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"m.value\"\n [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon\n [praxisIcon]=\"mpi2\"\n ></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt:\n config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr.color, tr.variant)\n \"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt ||\n ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (\n item.alertsData !== undefined &&\n item.ownerName\n ) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts\n [alerts]=\"item.alertsData\"\n ></praxis-executive-alerts>\n <praxis-executive-owner\n [name]=\"item.ownerName\"\n ></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, i)\n ? 'expand_less'\n : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon()\n ? isExpanded(item, i)\n : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n action.icon || 'more_horiz'\n \"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, i)\"\n [style.cssText]=\"\n actionIconStyle(action.color)\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"itemActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #itemActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, i)\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n </div>\n </div>\n }\n @if (shouldShowSelectionControl()) {\n <div class=\"list-selection-control\">\n @if (config.selection?.mode === \"multiple\") {\n <mat-checkbox\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, $event.checked)\"\n ></mat-checkbox>\n } @else {\n <mat-radio-button\n [name]=\"selectionControlName()\"\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, true)\"\n ></mat-radio-button>\n }\n </div>\n }\n </div>\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [ngClass]=\"expansionRenderingClasses()\"\n [style]=\"expansionRenderingStyle()\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @case (\"rich-content\") {\n @if (\n expansionRichContentDocument(\n item,\n expansionSection,\n i\n );\n as richExpansionDocument\n ) {\n <praxis-rich-content\n [document]=\"richExpansionDocument\"\n [context]=\"\n expansionRichContentContext(\n item,\n expansionSection,\n i\n )\n \"\n [hostCapabilities]=\"\n expansionRichContentHostCapabilities(\n item,\n expansionSection,\n i\n )\n \"\n rootClassName=\"praxis-list-expansion-rich-content\"\n ></praxis-rich-content>\n }\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"list-item-content card-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n @if (cardDetailSlots(it); as detailSlots) {\n @if (detailSlots.length) {\n <div class=\"card-detail-strip\">\n @for (detail of detailSlots; track detail.slot) {\n <div\n class=\"card-detail\"\n [ngClass]=\"'card-detail--' + detail.slot\"\n >\n <span class=\"card-detail__label\">{{\n detail.label\n }}</span>\n <span class=\"card-detail__value\">\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: detail.node,\n slot: detail.slot,\n imageAlt: rowLayoutImageAlt(detail.slot),\n }\n \"\n ></ng-container>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"tile-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @if (\n simpleRichContentNodes(tr2, {\n imageAlt: tr2.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr2.color, tr2.variant)\n \"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"tr2.value\"\n [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr2\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Remote pagination stays attached to the collection footer. -->\n @if (isRemoteDataMode() && !(error$ | async)) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (config.ui?.showRange === false) {\n <div class=\"list-paginator-total\" aria-live=\"polite\">\n {{ remoteTotalLabel(total) }}\n </div>\n }\n <mat-paginator\n [length]=\"total || 0\"\n [pageIndex]=\"ps.pageNumber || 0\"\n [pageSize]=\"ps.pageSize || config.layout?.pageSize || 10\"\n [pageSizeOptions]=\"listPageSizeOptions()\"\n [selectConfig]=\"paginatorSelectConfig\"\n [showFirstLastButtons]=\"true\"\n [class.hide-range]=\"config.ui?.showRange === false\"\n (page)=\"onPageChange($event)\"\n >\n </mat-paginator>\n }\n }\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{container-type:inline-size;--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var( --md-sys-color-on-primary-container, var(--md-sys-color-on-surface) );--p-list-grad-foreground-muted: color-mix( in srgb, var(--p-list-grad-foreground) 76%, transparent );--p-list-leading-width: 36px;--p-list-trailing-min-width: 140px;--p-list-trailing-max-width: 320px;--p-list-item-gap: 10px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 10px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .875rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 8px;--p-list-action-button-height: 32px;--p-list-tile-minW: 240px;--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-radius: 12px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-gradient-tile .tile-media{background:color-mix(in srgb,var(--md-sys-color-surface) 74%,transparent);border-color:color-mix(in srgb,var(--p-list-foreground) 22%,transparent)}.skin-gradient-tile .tile-media mat-icon,.skin-gradient-tile .tile-meta,.skin-gradient-tile .tile-trailing,.skin-gradient-tile .feature,.skin-gradient-tile .secondary,.skin-gradient-tile .meta{color:var(--p-list-foreground-muted)}.skin-gradient-tile .tile-status,.skin-gradient-tile [data-rich-node-type=badge] .prx-rich-badge{color:var(--md-sys-color-on-secondary-container, var(--p-list-foreground));background:var(--md-sys-color-secondary-container, rgba(255, 255, 255, .72))}.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 6px;--p-list-item-padding-x: 10px;--p-list-item-gap: 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.praxis-list-root.lines-3 .mat-mdc-list-item{min-height:68px}.density-compact{--p-list-tile-gap: 10px;--p-list-tile-padding: 10px;--p-list-tile-minW: 188px}.density-comfortable{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 4px;--p-list-tile-gap: 10px}.item-spacing-default{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{box-sizing:border-box;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),min(34vw,var(--p-list-trailing-max-width)));align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items);position:relative}.list-row-main-action{position:absolute;inset:0;z-index:1;padding:0;border:0;border-radius:inherit;background:transparent;cursor:pointer}.list-row-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{position:relative;z-index:0;min-width:0;height:100%;align-self:stretch;display:flex;align-items:var(--p-list-row-slot-align-items, center);gap:8px}.list-item-content--row-layout :is(.list-row-slot--actions,.list-row-slot--expand,.list-row-slot--trailing){z-index:2}.list-item-content--row-layout .list-row-slot>praxis-rich-content,.list-item-content--row-layout .list-row-slot>praxis-list-metric,.list-item-content--row-layout .list-row-slot>praxis-list-compose,.list-item-content--row-layout .list-row-slot>praxis-list-runtime-component{min-width:0}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary,.list-row-slot--identity{min-width:0}.list-row-slot--identity>praxis-list-compose,.list-row-slot--primary>praxis-list-compose,.list-row-slot--secondary>praxis-list-compose{width:100%}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:nowrap;justify-content:flex-end;gap:8px}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-width:0;min-height:100%}.list-item-leading>praxis-rich-content,.list-row-slot--leading>praxis-rich-content{min-width:0;max-width:100%}:host ::ng-deep .list-item-leading [data-rich-node-type=icon],:host ::ng-deep .list-row-slot--leading [data-rich-node-type=icon]{width:36px;height:36px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 14%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 28%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary, #06b6d4));box-sizing:border-box;flex-shrink:0}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:2px}.list-item-trailing{box-sizing:border-box;min-width:0;width:100%;max-width:var(--p-list-trailing-max-width);display:flex;flex-wrap:nowrap;align-self:center;align-content:center;align-items:center;justify-content:end;gap:8px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-trailing>*{align-self:center}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{width:max-content;justify-self:end;align-self:center;display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap;max-width:100%;min-height:var(--p-list-action-button-height)}.list-item-actions .mat-mdc-button-base{min-height:var(--p-list-action-button-height);height:var(--p-list-action-button-height);display:inline-flex;align-items:center}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item{min-height:40px}.density-comfortable .mat-mdc-list-item{min-height:46px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item{min-height:48px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list mat-list-item:not(:last-child),.praxis-list-root .mat-mdc-list-item:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:var(--p-list-radius, 12px);box-shadow:var(--p-list-shadow, 0 1px 3px rgba(0, 0, 0, .2))}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item:hover .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item:hover .list-item-content{border-color:var(--md-sys-color-primary, #6750a4);box-shadow:var(--md-sys-elevation-level2, 0 2px 6px rgba(0, 0, 0, .25))}.praxis-list-root[data-item-appearance=capsule] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-capsule .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:9999px;box-shadow:var(--p-list-shadow, none)}.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-item-content,.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-row-shell--selectable,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-row-shell--selectable{background:transparent;border:none;box-shadow:none;border-radius:0}.mat-mdc-list-item:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-shell{width:100%;min-width:0}.list-row-shell--selectable{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch;border-radius:calc(var(--p-list-radius) * .75);background:var(--p-list-item-surface);border:var(--p-list-item-border);color:var(--p-list-foreground);overflow:hidden;transition:background .15s ease,box-shadow .15s ease,border-color .15s ease}.list-row-shell--selectable.list-row-shell--with-control{grid-template-columns:minmax(0,1fr) auto}.list-selection-control{position:relative;z-index:2;display:flex;align-items:flex-start;justify-content:center;padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x) var(--p-list-item-padding-y) 0}.list-selection-control mat-radio-button{--mat-radio-selected-icon-color: var(--p-list-foreground);--mat-radio-selected-hover-icon-color: var(--p-list-foreground);--mat-radio-selected-focus-icon-color: var(--p-list-foreground);--mat-radio-selected-pressed-icon-color: var(--p-list-foreground);--mat-radio-checked-ripple-color: var(--p-list-foreground)}.praxis-list-root .mat-mdc-list-item .list-row-shell--selectable .list-item-content{background:transparent;border:0;border-radius:0;box-shadow:none}.mat-mdc-list-item:hover .list-row-shell--selectable{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-row-shell--selectable{background:var(--p-list-item-active-surface)}.list-row-shell--selected{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.skin-elevated .list-row-shell--selectable,.skin-outline .list-row-shell--selectable,.skin-flat .list-row-shell--selectable,.skin-neumorphism .list-row-shell--selectable{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-item-border);box-shadow:var(--p-list-shadow)}.skin-pill-soft .list-row-shell--selectable{border-radius:calc(var(--p-list-radius) * 1.3);background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-border);box-shadow:var(--md-sys-elevation-level1)}.skin-gradient-tile .list-row-shell--selectable{border-radius:var(--p-list-radius);background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));color:var(--p-list-foreground)}.skin-glass .list-row-shell--selectable{border-radius:var(--p-list-radius);background:var(--md-sys-color-surface-container-low);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #5b6f84;--p-list-chip-background: #eef4f8;--p-list-chip-color: #17324d;--p-list-chip-border-color: #d5e2ec;--md-sys-color-on-surface: #17324d;--md-sys-color-on-surface-variant: #5b6f84;--md-sys-color-surface: #ffffff;--md-sys-color-surface-container-low: #f1f5f9;--md-sys-color-surface-container: #e2e8f0;--md-sys-color-surface-container-high: #e2e8f0;--md-sys-color-surface-container-highest: #cbd5e1;--md-sys-color-outline: #94a3b8;--md-sys-color-outline-variant: #d5e2ec;--praxis-icon-btn-fg: #6d7f93;color:var(--p-list-foreground)}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 16px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}:host ::ng-deep .executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}:host ::ng-deep .executive-inline-skin .exec-balance-metric,:host ::ng-deep .executive-inline-skin .exec-limit-metric,:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:0;gap:5px}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__value,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:84px;justify-items:center}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:5px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__below-progress,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon .prx-rich-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{--praxis-icon-btn-fg: #6d7f93;width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb;color:var(--p-list-foreground)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;max-width:100%;min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta>span,.meta praxis-rich-content{min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta .mat-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;line-height:1;vertical-align:middle}.trailing{color:var(--p-list-foreground-muted);margin-left:0;max-width:100%;min-width:0;display:inline-flex;justify-content:flex-end;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trailing praxis-rich-content{min-width:0}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge]{background:transparent;color:inherit}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge{min-height:22px;padding:2px 10px;border-radius:999px;font-size:.72rem;font-weight:600;letter-spacing:.02em;border:1px solid var(--p-list-chip-border-color, transparent);background:var(--p-list-chip-background, var(--md-sys-color-primary-container, #e8def8));color:var(--p-list-chip-color, var(--md-sys-color-on-primary-container, #21005d));line-height:18px}.section-header{display:block;font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.section-header praxis-rich-content{display:block;width:100%}.section-header--setup{margin:8px 12px 12px;padding:14px 16px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:color-mix(in srgb,var(--p-list-surface) 92%,var(--md-sys-color-primary) 8%);color:var(--p-list-foreground);font-weight:500}praxis-empty-state-card.section-header,praxis-empty-state-card.section-header--setup{margin:0;padding:0;border:0;border-radius:0;background:transparent;font-size:inherit;font-weight:inherit}.praxis-list-root mat-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:var(--p-list-expansion-padding, 14px 16px);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75);color:var(--p-list-foreground);white-space:normal;min-width:0}.praxis-list-root[data-item-appearance=card] .list-row-shell--expanded .list-item-content,.praxis-list-root.item-appearance-card .list-row-shell--expanded .list-item-content{border-bottom-left-radius:0;border-bottom-right-radius:0}.praxis-list-root[data-item-appearance=card] .item-expansion--attached,.praxis-list-root.item-appearance-card .item-expansion--attached{margin:0;border-top:0;border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:var(--p-list-radius, 12px);border-bottom-right-radius:var(--p-list-radius, 12px);background:color-mix(in srgb,var(--md-sys-color-surface-container-low, var(--p-list-surface)) 82%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 65%,transparent)}.skin-glass .item-expansion--attached{backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.item-expansion--detached,.item-expansion--modal{margin-top:var(--p-list-item-stack-gap);background:var(--md-sys-color-surface-container, var(--p-list-surface));box-shadow:var(--md-sys-elevation-level1)}.item-expansion--modal{border-color:var(--md-sys-color-outline);box-shadow:var(--md-sys-elevation-level3)}.item-expansion-grid{display:grid;grid-template-columns:var(--p-list-expansion-columns, repeat(auto-fit, minmax(220px, 1fr)));gap:var(--p-list-expansion-gap, 16px)}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;min-width:0;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground);white-space:normal;overflow-wrap:break-word}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted);white-space:normal;overflow-wrap:break-word}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px 12px}.expansion-key-value-row{display:grid;align-content:start;gap:3px;min-width:0;overflow:hidden;padding:8px 10px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-surface-container-highest, rgba(255, 255, 255, .04)) 45%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 45%,transparent)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0;min-width:0;white-space:normal;overflow-wrap:break-word}.expansion-key-value-row dt{font-size:.68rem;font-weight:700;line-height:1.25;letter-spacing:.05em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.85rem;font-weight:600;line-height:1.35;color:var(--p-list-foreground)}.cards-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, max(300px, var(--p-list-tile-minW)))), 1fr)));gap:max(var(--p-list-tile-gap),16px)}.tiles-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, var(--p-list-tile-minW))), 1fr)));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.tile-main-action{display:flex;flex:1;min-width:0;flex-direction:column;gap:10px;color:inherit;cursor:pointer}.tile-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid,.cards-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:max(var(--p-list-tile-padding),16px);display:flex;flex-direction:column;gap:var(--p-list-item-gap);min-height:var(--p-list-card-minH, 220px);position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.density-compact .item-card{min-height:var(--p-list-card-minH, 148px)}.pdx-list-item--primary{--p-list-item-rule-tone: var(--md-sys-color-primary, #06b6d4);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 52%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--success{--p-list-item-rule-tone: var(--p-color-success, #10b981);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 48%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--warning{--p-list-item-rule-tone: var( --p-color-warning, var(--md-sys-color-tertiary, #f59e0b) );border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 54%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 10%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--danger{--p-list-item-rule-tone: var(--md-sys-color-error, #ef4444);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 56%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 11%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--muted{opacity:.78;border-style:dashed!important;background:color-mix(in srgb,var(--md-sys-color-surface-variant) 34%,var(--p-list-surface))!important}.pdx-list-item--neutral{border-color:var(--md-sys-color-outline-variant)!important;background:var(--p-list-surface)!important}.card-main-action{display:block;width:100%;min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.card-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.item-card .list-item-content{display:block;padding:0;min-width:0;overflow:hidden}.item-card .list-item-leading{position:absolute;top:18px;left:18px;min-height:0;z-index:1}.item-card .leading-placeholder{width:36px;height:36px}.item-card .leading-icon.mat-icon,.item-card .list-item-leading>mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent));color:var(--md-sys-color-primary)}.item-card .list-item-text{display:grid;gap:9px;padding-left:50px;width:100%;min-width:0;box-sizing:border-box}.item-card .primary{padding-right:min(50%,160px);font-size:1rem;font-weight:800;letter-spacing:-.01em;line-height:1.18;min-width:0;overflow-wrap:anywhere}.item-card .secondary{color:var(--p-list-foreground-muted);font-weight:600;line-height:1.35;min-width:0;overflow-wrap:anywhere}.item-card .features{display:flex;flex-direction:column;gap:8px;margin-top:2px}.item-card .feature{display:inline-flex;align-items:start;gap:8px;min-width:0;max-width:100%;overflow-wrap:anywhere}.item-card .feature mat-icon{margin-top:1px;color:var(--p-list-foreground-muted);opacity:.86}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width);grid-column:1/-1;align-items:stretch;padding-right:0}.card-detail-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:10px;margin-top:16px}.card-detail{min-width:0;padding:11px 12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 22%,transparent),color-mix(in srgb,var(--p-list-surface) 92%,transparent));box-shadow:inset 0 1px #ffffff14}.card-detail__label{display:block;margin-bottom:3px;color:var(--p-list-foreground-muted);font-size:.68rem;font-weight:700;letter-spacing:.08em;line-height:1.1;text-transform:uppercase}.card-detail__value{display:block;min-width:0;color:var(--p-list-foreground);font-size:.94rem;font-weight:800;line-height:1.2;overflow-wrap:normal;word-break:normal}.card-detail__value,.card-detail__value *{white-space:nowrap}.card-detail--balance .card-detail__value{color:var(--md-sys-color-primary)}.card-detail--limit .card-detail__value{color:var(--md-sys-color-error)}.card-detail--risk .card-detail__value{color:var(--md-sys-color-tertiary, var(--p-list-foreground))}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);margin-top:auto}.status-overlay{position:absolute;top:14px;right:14px;max-width:min(42%,148px);overflow:hidden;pointer-events:none}.status-overlay .mat-mdc-chip{pointer-events:auto;width:100%;min-width:0;max-width:100%}.status-overlay .mdc-evolution-chip__text-label,.status-overlay .mat-mdc-chip-action-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.leading-icon.mat-icon,.list-item-leading>mat-icon,.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon],[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon]{width:36px;height:36px;min-width:36px;line-height:36px;font-size:19px;display:inline-flex;align-items:center;justify-content:center;border-radius:10px;box-sizing:border-box;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 15%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 30%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary));box-shadow:inset 0 1px #ffffff0f}.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon,[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon{font-size:19px;width:19px;height:19px;line-height:19px;color:inherit}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);--mdc-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mat-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mdc-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mat-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mdc-chip-outline-color: var(--p-list-chip-border-color, transparent);--mat-chip-outline-color: var(--p-list-chip-border-color, transparent);font-size:var(--p-list-chip-font-size);font-weight:600;letter-spacing:.02em;border-radius:999px!important;background-color:var(--p-list-chip-background, var(--md-sys-color-surface-container-high))!important;color:var(--p-list-chip-color, var(--md-sys-color-on-surface))!important;border:1px solid var(--p-list-chip-border-color, transparent)!important}:host ::ng-deep .mat-mdc-chip .mdc-evolution-chip__text-label,:host ::ng-deep .mat-mdc-chip .mat-mdc-chip-action-label{color:var(--p-list-chip-color, inherit)!important;font-weight:600;font-size:.72rem;letter-spacing:.02em}.meta .mat-icon{font-size:18px;height:18px;width:18px}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important;color:var(--p-list-chip-color, currentColor)!important}.w-60{width:60%}.w-40{width:40%}.list-collection-toolbar{display:flex;align-items:center;gap:12px;padding:12px;margin-bottom:8px;color:var(--p-list-foreground);background:var(--p-list-surface-low);border:var(--p-list-border);border-radius:calc(var(--p-list-radius) * .75)}.list-toolbar-search{flex:1 1 320px;min-width:220px;max-width:440px}.list-toolbar-commands{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-inline-start:auto}.list-toolbar-commands button{border-radius:8px}.list-toolbar-commands button .mat-icon{margin-right:6px}.list-toolbar-sort{width:200px}.list-remote-error{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;margin:8px 4px 0;padding:16px;color:var(--md-sys-color-on-error-container);background:var(--md-sys-color-error-container);border-radius:calc(var(--p-list-radius) * .75)}.list-remote-error__copy{display:flex;flex-direction:column;gap:4px;min-width:0}.list-remote-error__copy span{color:color-mix(in srgb,var(--md-sys-color-on-error-container) 82%,transparent);line-height:1.45}.list-remote-error button{color:var(--md-sys-color-on-error-container);--mat-button-outlined-label-text-color: var( --md-sys-color-on-error-container );--mat-button-outlined-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent );--mdc-outlined-button-label-text-color: var( --md-sys-color-on-error-container );--mdc-outlined-button-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent )}.mat-mdc-paginator{margin-top:14px;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--p-list-surface-low);color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-container{min-height:40px;padding:4px 8px;gap:6px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select{margin-left:8px;width:92px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-text-field-wrapper{--mdc-outlined-text-field-container-color: color-mix( in srgb, var(--p-list-surface-low) 92%, var(--md-sys-color-on-surface) 8% );--mdc-outlined-text-field-input-text-color: var(--p-list-foreground);min-height:40px;padding-inline:12px 8px;background:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;background-color:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;color:var(--p-list-foreground)!important}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-form-field-infix{min-height:40px;padding-block:8px;width:auto}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-select-trigger{min-height:24px;padding-right:2px;color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-range-label,:host ::ng-deep .mat-mdc-paginator .mat-mdc-select-value-text{font-size:12px;color:var(--p-list-foreground-muted)}.list-paginator-total{margin-top:14px;padding:4px 8px 0;font-size:12px;color:var(--p-list-foreground-muted)}:host ::ng-deep .mat-mdc-paginator.hide-range .mat-mdc-paginator-range-label{display:none}::ng-deep .praxis-list-paginator-select-panel.mat-mdc-select-panel{--mat-select-panel-background-color: var( --md-sys-color-surface-container, var(--mat-sys-surface-container) );background:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;background-color:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 70%,transparent);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, #000) 28%,transparent)}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option{--mat-option-label-text-color: var(--md-sys-color-on-surface, #111827);color:var(--md-sys-color-on-surface, #111827)!important}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled),::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option.mat-mdc-option-active{--mat-option-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-primary, #2f7cff) 14%, transparent );background:color-mix(in srgb,var(--md-sys-color-primary, #2f7cff) 14%,transparent)!important;color:var(--md-sys-color-on-surface, #111827)!important}.muted{color:var(--p-list-foreground-muted)}@container (max-width: 720px){.executive-inline-skin .list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.executive-inline-skin .list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--primary,.executive-inline-skin .list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.executive-inline-skin .list-item-content--row-layout .list-row-slot--meta,.executive-inline-skin .list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.executive-inline-skin .list-selection-control{padding-left:0}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.executive-inline-skin .list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.executive-inline-skin .list-item-trailing .list-item-actions{margin-inline-start:auto}.executive-inline-skin .item-expansion{margin-left:0;margin-right:0}.executive-inline-skin .list-collection-toolbar{flex-direction:column;align-items:stretch}.executive-inline-skin .list-toolbar-search,.executive-inline-skin .list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.executive-inline-skin .list-toolbar-commands{width:100%;margin-inline-start:0}.executive-inline-skin .list-toolbar-sort{flex:1 1 100%}.executive-inline-skin .list-toolbar-commands button{flex:0 0 auto}.executive-inline-skin .list-remote-error{grid-template-columns:auto minmax(0,1fr)}.executive-inline-skin .list-remote-error button{grid-column:1/-1;justify-self:stretch}}@container (max-width: 420px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}@media(max-width:640px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}.list-loading-status{display:flex;align-items:center;gap:8px;padding:12px 0;color:inherit;--mat-progress-spinner-active-indicator-color: currentColor}.list-loading-status:empty{display:none}.praxis-list-virtual-viewport,.praxis-list-bounded-viewport{display:block;width:100%;overflow-y:auto;outline:none;padding-right:4px;box-sizing:border-box;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent) transparent}.praxis-list-virtual-viewport::-webkit-scrollbar,.praxis-list-bounded-viewport::-webkit-scrollbar{width:6px;height:6px}.praxis-list-virtual-viewport::-webkit-scrollbar-track,.praxis-list-bounded-viewport::-webkit-scrollbar-track{background:transparent}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent);border-radius:999px}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb:hover,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--md-sys-color-on-surface-variant, #94a3b8) 72%,transparent)}.praxis-list-virtual-viewport{height:var(--p-list-viewport-height, 400px);contain:strict}.praxis-list-virtual-viewport .praxis-list-virtual-list{padding-top:0;padding-bottom:0}.list-item-menu-trigger{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--md-sys-shape-corner-full, 9999px);color:var(--p-list-foreground-muted, inherit);transition:background-color .15s ease,color .15s ease}.list-item-menu-trigger:hover{background-color:var(--p-list-item-hover-surface, rgba(0, 0, 0, .04));color:var(--p-list-foreground, inherit)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2$1.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i2$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i2$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3.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: MatRadioModule }, { kind: "component", type: i4$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i7.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i7.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", 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: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i9.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i11.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4$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: i4$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.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: MatTooltipModule }, { kind: "directive", type: i14.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisAiAssistantShellComponent, selector: "praxis-ai-assistant-shell", inputs: ["labels", "mode", "state", "contextItems", "attachments", "messages", "quickReplies", "recommendedIntents", "prompt", "statusText", "errorText", "testIdPrefix", "panelTestId", "submitTestId", "applyTestId", "primaryAction", "secondaryActions", "governanceActions", "busy", "canSubmit", "canApply", "submitOnEnter", "showAttachAction", "enablePastedAttachments", "enableFileAttachments", "attachmentAccept", "attachmentMultiple", "voiceInputMode", "voiceLanguage", "draggable", "resizable", "minWidth", "minHeight", "margin", "layout"], outputs: ["promptChange", "submitPrompt", "apply", "retryTurn", "cancelTurn", "shellAction", "close", "attach", "attachmentsPasted", "attachmentsSelected", "removeAttachment", "messageAction", "editMessage", "resendMessage", "quickReply", "recommendedIntent", "layoutChange"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone", "variant", "alignment", "density", "iconContainer"] }, { kind: "component", type: ExecutiveBadgeComponent, selector: "praxis-executive-badge", inputs: ["ariaLabel", "label", "variant"] }, { kind: "component", type: ExecutiveAlertsComponent, selector: "praxis-executive-alerts", inputs: ["alerts"] }, { kind: "component", type: ExecutiveOwnerComponent, selector: "praxis-executive-owner", inputs: ["name"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"], outputs: ["nodeAction"] }, { kind: "component", type: PraxisListMetricComponent, selector: "praxis-list-metric", inputs: ["metric"] }, { kind: "component", type: PraxisListComposeComponent, selector: "praxis-list-compose", inputs: ["compose"] }, { kind: "component", type: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i15.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i15.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i15.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12934
13358
|
}
|
|
12935
13359
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisList, decorators: [{
|
|
12936
13360
|
type: Component,
|
|
@@ -12955,6 +13379,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
12955
13379
|
MatInputModule,
|
|
12956
13380
|
MatTooltipModule,
|
|
12957
13381
|
PraxisAiAssistantShellComponent,
|
|
13382
|
+
EmptyStateCardComponent,
|
|
12958
13383
|
ExecutiveBadgeComponent,
|
|
12959
13384
|
ExecutiveAlertsComponent,
|
|
12960
13385
|
ExecutiveOwnerComponent,
|
|
@@ -12968,7 +13393,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
12968
13393
|
ListDataService,
|
|
12969
13394
|
MatPaginatorIntl,
|
|
12970
13395
|
providePraxisListI18n(),
|
|
12971
|
-
], template: "<div class=\"list-loading-status\" role=\"status\">\n @if (loading$ | async) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"20\" aria-hidden=\"true\"></mat-progress-spinner>\n <span>{{ t('loading', 'Carregando itens\u2026') }}</span>\n }\n</div>\n<div\n class=\"praxis-list-root\"\n tabindex=\"-1\"\n [attr.aria-busy]=\"(loading$ | async) ? 'true' : 'false'\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.data-item-appearance]=\"config?.layout?.itemAppearance || null\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openAiAssistant()\"\n matTooltip=\"Copiloto semantico Praxis\"\n aria-label=\"Abrir copiloto semantico Praxis da lista\"\n data-testid=\"praxis-list-ai-assistant-trigger\"\n >\n <mat-icon [praxisIcon]=\"'auto_awesome'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"\n aiAssistantViewState.state === 'processing' ||\n aiAssistantViewState.state === 'applying'\n \"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-list-ai-assistant\"\n panelTestId=\"praxis-list-ai-assistant-panel\"\n submitTestId=\"praxis-list-ai-assistant-submit\"\n applyTestId=\"praxis-list-ai-assistant-apply\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply()\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n (close)=\"closeAiAssistant()\"\n ></praxis-ai-assistant-shell>\n }\n\n @if (\n config.export?.enabled ||\n (isRemoteDataMode() &&\n (config.ui?.showSort ||\n (config.ui?.showSearch && config.ui?.searchField)))\n ) {\n <div\n class=\"list-collection-toolbar\"\n role=\"group\"\n [attr.aria-label]=\"t('toolbar.label', 'Controles da lista')\"\n >\n @if (\n isRemoteDataMode() && config.ui?.showSearch && config.ui?.searchField\n ) {\n <mat-form-field\n class=\"list-toolbar-search\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{\n config.ui?.searchPlaceholder || t(\"toolbar.search\", \"Buscar\")\n }}</mat-label>\n <mat-icon matPrefix [praxisIcon]=\"'search'\"></mat-icon>\n <input\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n\n <div class=\"list-toolbar-commands\">\n @if (isRemoteDataMode() && config.ui?.showSort) {\n <mat-form-field\n class=\"list-toolbar-sort\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{ t(\"toolbar.sort\", \"Ordenar por\") }}</mat-label>\n @let activeSort = activeSortValue((page$ | async)?.sort);\n <mat-select\n [value]=\"activeSort\"\n (selectionChange)=\"onSortChange($event.value)\"\n >\n @if (activeSort && !hasSortOption(activeSort)) {\n <mat-option [value]=\"activeSort\">{{ activeSort }}</mat-option>\n }\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @if (config.export?.enabled) {\n <button\n mat-stroked-button\n type=\"button\"\n [matMenuTriggerFor]=\"listExportMenu\"\n [attr.aria-label]=\"t('export.button', 'Exportar')\"\n [disabled]=\"exportBusy\"\n [attr.aria-busy]=\"exportBusy\"\n >\n <mat-icon [praxisIcon]=\"'download'\"></mat-icon>\n {{ t(\"export.button\", \"Exportar\") }}\n </button>\n <span class=\"cdk-visually-hidden\" aria-live=\"polite\">\n {{ exportStatusMessage }}\n </span>\n <mat-menu #listExportMenu=\"matMenu\">\n @for (format of listExportFormats(); track format) {\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"onExportAction(format)\"\n >\n <mat-icon [praxisIcon]=\"exportIcon(format)\"></mat-icon>\n {{ format.toUpperCase() }}\n </button>\n }\n </mat-menu>\n }\n </div>\n </div>\n }\n\n <!-- Skeleton while loading -->\n @if (loading$ | async) {\n @if (hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n @if (error$ | async; as remoteError) {\n <div class=\"list-remote-error\" role=\"alert\">\n <mat-icon [praxisIcon]=\"'error_outline'\"></mat-icon>\n <div class=\"list-remote-error__copy\">\n <strong>{{\n t(\"remoteError.title\", \"N\u00E3o foi poss\u00EDvel carregar a lista\")\n }}</strong>\n <span>\n {{\n remoteError.filtered\n ? t(\n \"remoteError.filteredDescription\",\n \"Os filtros permanecem aplicados. Nenhum dado sem filtro foi exibido.\"\n )\n : t(\n \"remoteError.description\",\n \"Verifique a conex\u00E3o e tente novamente.\"\n )\n }}\n </span>\n </div>\n <button mat-stroked-button type=\"button\" (click)=\"retryRemoteData()\">\n {{ t(\"remoteError.retry\", \"Tentar novamente\") }}\n </button>\n </div>\n }\n\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0 && !(error$ | async)) {\n <div\n class=\"section-header\"\n [class.section-header--setup]=\"isResourceConnectionMissing()\"\n >\n @if (emptyStateTemplate(); as empty) {\n @if (\n simpleRichContentNodes(empty, {\n imageAlt: config.templating?.emptyState?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @if (\n simpleRichContentNodes(node, { slot: slot, imageAlt: imageAlt });\n as richNodes\n ) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"[\n slot === 'leading' ? 'leading-icon' : '',\n node?.class || '',\n ]\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n slot === 'leading'\n ? leadingIconStyle(node?.color, node?.style)\n : (node?.style || '' ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img\n [src]=\"node?.value\"\n [alt]=\"node?.imageAlt || imageAlt || ''\"\n />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (\n slot === \"meta\" && config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n }\n </ng-template>\n\n <ng-template #featureContent let-item let-feature=\"feature\">\n @if (featureTemplateNode(item, feature); as featureNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: featureNode,\n slot: 'feature',\n imageAlt: feature?.imageAlt || '',\n }\n \"\n ></ng-container>\n } @else if (featureRichContentNodes(item, feature); as featureNodes) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (feature.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"feature.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"feature.class\" [style.cssText]=\"feature.style\">\n @for (line of featureLabelLines(item, feature.expr); track $index) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, feature.expr, feature.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n >\n @if (clickable) {\n <button\n type=\"button\"\n class=\"list-row-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, index) : null\n \"\n (click)=\"onRowActivate(item, index, sectionKey)\"\n ></button>\n }\n @for (\n column of rowLayoutColumns();\n track rowLayoutTrackColumn($index, column)\n ) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"rowActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #rowActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, index)\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection and row actions share one neutral list shell so every\n interactive affordance remains a sibling keyboard target. -->\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n\n <!-- Unified list surface -->\n <ng-template #readList>\n @if (isVirtualScrollEnabled()) {\n <cdk-virtual-scroll-viewport\n class=\"praxis-list-virtual-viewport\"\n [itemSize]=\"virtualScrollItemSize()\"\n [minBufferPx]=\"virtualScrollMinBufferPx()\"\n [maxBufferPx]=\"virtualScrollMaxBufferPx()\"\n [style.height]=\"virtualScrollViewportHeight()\"\n >\n <mat-list\n class=\"praxis-list-virtual-list\"\n role=\"list\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n <mat-list-item\n *cdkVirtualFor=\"\n let item of virtualScrollItems(sections$ | async, items$ | async);\n let i = index;\n trackBy: trackByVirtualItem\n \"\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n </mat-list>\n </cdk-virtual-scroll-viewport>\n } @else {\n <mat-list\n role=\"list\"\n [class.praxis-list-bounded-viewport]=\"hasBoundedScrollViewport()\"\n [style.max-height]=\"hasBoundedScrollViewport() ? virtualScrollViewportHeight() : null\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n @for (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt:\n config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') +\n iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"sh\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider\n role=\"presentation\"\n aria-hidden=\"true\"\n ></mat-divider>\n }\n }\n }\n </mat-list>\n }\n </ng-template>\n\n <ng-template #listItemBody let-item let-i=\"index\" let-sectionKey=\"sectionKey\">\n <div\n class=\"list-row-shell\"\n [class.list-row-shell--selectable]=\"isSelectionEnabled()\"\n [class.list-row-shell--with-control]=\"shouldShowSelectionControl()\"\n [class.list-row-shell--selected]=\"isItemSelected(item)\"\n [class.list-row-shell--expanded]=\"isExpandable() && isExpanded(item, i)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: sectionKey,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"\n onRowActivate(item, i, sectionKey)\n \"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt:\n config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt ||\n ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(primary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(secondary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (\n item.segmentVariant &&\n item.segmentLabel &&\n item.accountType &&\n item.since\n ) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge\n [variant]=\"item.segmentVariant\"\n [label]=\"item.segmentLabel\"\n ></praxis-executive-badge>\n <span class=\"exec-subcopy\">{{\n item.accountType\n }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\"\n >Desde {{ item.since }}</span\n >\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span\n [innerHTML]=\"secondary(item)?.value\"\n ></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (\n secondary(item)?.type === \"component\"\n ) {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: item, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, { slot: \"meta\" });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(m.color, m.variant)\n \"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"m.value\"\n [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon\n [praxisIcon]=\"mpi2\"\n ></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt:\n config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr.color, tr.variant)\n \"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt ||\n ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (\n item.alertsData !== undefined &&\n item.ownerName\n ) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts\n [alerts]=\"item.alertsData\"\n ></praxis-executive-alerts>\n <praxis-executive-owner\n [name]=\"item.ownerName\"\n ></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, i)\n ? 'expand_less'\n : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon()\n ? isExpanded(item, i)\n : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n action.icon || 'more_horiz'\n \"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, i)\"\n [style.cssText]=\"\n actionIconStyle(action.color)\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"itemActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #itemActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, i)\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n </div>\n </div>\n }\n @if (shouldShowSelectionControl()) {\n <div class=\"list-selection-control\">\n @if (config.selection?.mode === \"multiple\") {\n <mat-checkbox\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, $event.checked)\"\n ></mat-checkbox>\n } @else {\n <mat-radio-button\n [name]=\"selectionControlName()\"\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, true)\"\n ></mat-radio-button>\n }\n </div>\n }\n </div>\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [ngClass]=\"expansionRenderingClasses()\"\n [style]=\"expansionRenderingStyle()\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @case (\"rich-content\") {\n @if (\n expansionRichContentDocument(\n item,\n expansionSection,\n i\n );\n as richExpansionDocument\n ) {\n <praxis-rich-content\n [document]=\"richExpansionDocument\"\n [context]=\"\n expansionRichContentContext(\n item,\n expansionSection,\n i\n )\n \"\n [hostCapabilities]=\"\n expansionRichContentHostCapabilities(\n item,\n expansionSection,\n i\n )\n \"\n rootClassName=\"praxis-list-expansion-rich-content\"\n ></praxis-rich-content>\n }\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"list-item-content card-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n @if (cardDetailSlots(it); as detailSlots) {\n @if (detailSlots.length) {\n <div class=\"card-detail-strip\">\n @for (detail of detailSlots; track detail.slot) {\n <div\n class=\"card-detail\"\n [ngClass]=\"'card-detail--' + detail.slot\"\n >\n <span class=\"card-detail__label\">{{\n detail.label\n }}</span>\n <span class=\"card-detail__value\">\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: detail.node,\n slot: detail.slot,\n imageAlt: rowLayoutImageAlt(detail.slot),\n }\n \"\n ></ng-container>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"tile-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @if (\n simpleRichContentNodes(tr2, {\n imageAlt: tr2.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr2.color, tr2.variant)\n \"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"tr2.value\"\n [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr2\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Remote pagination stays attached to the collection footer. -->\n @if (isRemoteDataMode() && !(error$ | async)) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (config.ui?.showRange === false) {\n <div class=\"list-paginator-total\" aria-live=\"polite\">\n {{ remoteTotalLabel(total) }}\n </div>\n }\n <mat-paginator\n [length]=\"total || 0\"\n [pageIndex]=\"ps.pageNumber || 0\"\n [pageSize]=\"ps.pageSize || config.layout?.pageSize || 10\"\n [pageSizeOptions]=\"listPageSizeOptions()\"\n [selectConfig]=\"paginatorSelectConfig\"\n [showFirstLastButtons]=\"true\"\n [class.hide-range]=\"config.ui?.showRange === false\"\n (page)=\"onPageChange($event)\"\n >\n </mat-paginator>\n }\n }\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{container-type:inline-size;--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var( --md-sys-color-on-primary-container, var(--md-sys-color-on-surface) );--p-list-grad-foreground-muted: color-mix( in srgb, var(--p-list-grad-foreground) 76%, transparent );--p-list-leading-width: 36px;--p-list-trailing-min-width: 140px;--p-list-trailing-max-width: 320px;--p-list-item-gap: 10px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 10px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .875rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 8px;--p-list-action-button-height: 32px;--p-list-tile-minW: 240px;--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-radius: 12px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-gradient-tile .tile-media{background:color-mix(in srgb,var(--md-sys-color-surface) 74%,transparent);border-color:color-mix(in srgb,var(--p-list-foreground) 22%,transparent)}.skin-gradient-tile .tile-media mat-icon,.skin-gradient-tile .tile-meta,.skin-gradient-tile .tile-trailing,.skin-gradient-tile .feature,.skin-gradient-tile .secondary,.skin-gradient-tile .meta{color:var(--p-list-foreground-muted)}.skin-gradient-tile .tile-status,.skin-gradient-tile [data-rich-node-type=badge] .prx-rich-badge{color:var(--md-sys-color-on-secondary-container, var(--p-list-foreground));background:var(--md-sys-color-secondary-container, rgba(255, 255, 255, .72))}.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 6px;--p-list-item-padding-x: 10px;--p-list-item-gap: 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.praxis-list-root.lines-3 .mat-mdc-list-item{min-height:68px}.density-compact{--p-list-tile-gap: 10px;--p-list-tile-padding: 10px;--p-list-tile-minW: 188px}.density-comfortable{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 4px;--p-list-tile-gap: 10px}.item-spacing-default{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{box-sizing:border-box;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),min(34vw,var(--p-list-trailing-max-width)));align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items);position:relative}.list-row-main-action{position:absolute;inset:0;z-index:1;padding:0;border:0;border-radius:inherit;background:transparent;cursor:pointer}.list-row-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{position:relative;z-index:0;min-width:0;height:100%;align-self:stretch;display:flex;align-items:var(--p-list-row-slot-align-items, center);gap:8px}.list-item-content--row-layout :is(.list-row-slot--actions,.list-row-slot--expand,.list-row-slot--trailing){z-index:2}.list-item-content--row-layout .list-row-slot>praxis-rich-content,.list-item-content--row-layout .list-row-slot>praxis-list-metric,.list-item-content--row-layout .list-row-slot>praxis-list-compose,.list-item-content--row-layout .list-row-slot>praxis-list-runtime-component{min-width:0}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary,.list-row-slot--identity{min-width:0}.list-row-slot--identity>praxis-list-compose,.list-row-slot--primary>praxis-list-compose,.list-row-slot--secondary>praxis-list-compose{width:100%}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:nowrap;justify-content:flex-end;gap:8px}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-width:0;min-height:100%}.list-item-leading>praxis-rich-content,.list-row-slot--leading>praxis-rich-content{min-width:0;max-width:100%}:host ::ng-deep .list-item-leading [data-rich-node-type=icon],:host ::ng-deep .list-row-slot--leading [data-rich-node-type=icon]{width:36px;height:36px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 14%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 28%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary, #06b6d4));box-sizing:border-box;flex-shrink:0}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:2px}.list-item-trailing{box-sizing:border-box;min-width:0;width:100%;max-width:var(--p-list-trailing-max-width);display:flex;flex-wrap:nowrap;align-self:center;align-content:center;align-items:center;justify-content:end;gap:8px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-trailing>*{align-self:center}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{width:max-content;justify-self:end;align-self:center;display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap;max-width:100%;min-height:var(--p-list-action-button-height)}.list-item-actions .mat-mdc-button-base{min-height:var(--p-list-action-button-height);height:var(--p-list-action-button-height);display:inline-flex;align-items:center}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item{min-height:40px}.density-comfortable .mat-mdc-list-item{min-height:46px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item{min-height:48px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list mat-list-item:not(:last-child),.praxis-list-root .mat-mdc-list-item:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:var(--p-list-radius, 12px);box-shadow:var(--p-list-shadow, 0 1px 3px rgba(0, 0, 0, .2))}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item:hover .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item:hover .list-item-content{border-color:var(--md-sys-color-primary, #6750a4);box-shadow:var(--md-sys-elevation-level2, 0 2px 6px rgba(0, 0, 0, .25))}.praxis-list-root[data-item-appearance=capsule] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-capsule .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:9999px;box-shadow:var(--p-list-shadow, none)}.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-item-content,.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-row-shell--selectable,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-row-shell--selectable{background:transparent;border:none;box-shadow:none;border-radius:0}.mat-mdc-list-item:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-shell{width:100%;min-width:0}.list-row-shell--selectable{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch;border-radius:calc(var(--p-list-radius) * .75);background:var(--p-list-item-surface);border:var(--p-list-item-border);color:var(--p-list-foreground);overflow:hidden;transition:background .15s ease,box-shadow .15s ease,border-color .15s ease}.list-row-shell--selectable.list-row-shell--with-control{grid-template-columns:minmax(0,1fr) auto}.list-selection-control{position:relative;z-index:2;display:flex;align-items:flex-start;justify-content:center;padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x) var(--p-list-item-padding-y) 0}.list-selection-control mat-radio-button{--mat-radio-selected-icon-color: var(--p-list-foreground);--mat-radio-selected-hover-icon-color: var(--p-list-foreground);--mat-radio-selected-focus-icon-color: var(--p-list-foreground);--mat-radio-selected-pressed-icon-color: var(--p-list-foreground);--mat-radio-checked-ripple-color: var(--p-list-foreground)}.praxis-list-root .mat-mdc-list-item .list-row-shell--selectable .list-item-content{background:transparent;border:0;border-radius:0;box-shadow:none}.mat-mdc-list-item:hover .list-row-shell--selectable{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-row-shell--selectable{background:var(--p-list-item-active-surface)}.list-row-shell--selected{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.skin-elevated .list-row-shell--selectable,.skin-outline .list-row-shell--selectable,.skin-flat .list-row-shell--selectable,.skin-neumorphism .list-row-shell--selectable{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-item-border);box-shadow:var(--p-list-shadow)}.skin-pill-soft .list-row-shell--selectable{border-radius:calc(var(--p-list-radius) * 1.3);background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-border);box-shadow:var(--md-sys-elevation-level1)}.skin-gradient-tile .list-row-shell--selectable{border-radius:var(--p-list-radius);background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));color:var(--p-list-foreground)}.skin-glass .list-row-shell--selectable{border-radius:var(--p-list-radius);background:var(--md-sys-color-surface-container-low);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #5b6f84;--p-list-chip-background: #eef4f8;--p-list-chip-color: #17324d;--p-list-chip-border-color: #d5e2ec;--md-sys-color-on-surface: #17324d;--md-sys-color-on-surface-variant: #5b6f84;--md-sys-color-surface: #ffffff;--md-sys-color-surface-container-low: #f1f5f9;--md-sys-color-surface-container: #e2e8f0;--md-sys-color-surface-container-high: #e2e8f0;--md-sys-color-surface-container-highest: #cbd5e1;--md-sys-color-outline: #94a3b8;--md-sys-color-outline-variant: #d5e2ec;--praxis-icon-btn-fg: #6d7f93;color:var(--p-list-foreground)}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 16px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}:host ::ng-deep .executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}:host ::ng-deep .executive-inline-skin .exec-balance-metric,:host ::ng-deep .executive-inline-skin .exec-limit-metric,:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:0;gap:5px}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__value,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:84px;justify-items:center}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:5px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__below-progress,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon .prx-rich-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{--praxis-icon-btn-fg: #6d7f93;width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb;color:var(--p-list-foreground)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;max-width:100%;min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta>span,.meta praxis-rich-content{min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta .mat-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;line-height:1;vertical-align:middle}.trailing{color:var(--p-list-foreground-muted);margin-left:0;max-width:100%;min-width:0;display:inline-flex;justify-content:flex-end;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trailing praxis-rich-content{min-width:0}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge]{background:transparent;color:inherit}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge{min-height:22px;padding:2px 10px;border-radius:999px;font-size:.72rem;font-weight:600;letter-spacing:.02em;border:1px solid var(--p-list-chip-border-color, transparent);background:var(--p-list-chip-background, var(--md-sys-color-primary-container, #e8def8));color:var(--p-list-chip-color, var(--md-sys-color-on-primary-container, #21005d));line-height:18px}.section-header{display:block;font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.section-header praxis-rich-content{display:block;width:100%}.section-header--setup{margin:8px 12px 12px;padding:14px 16px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:color-mix(in srgb,var(--p-list-surface) 92%,var(--md-sys-color-primary) 8%);color:var(--p-list-foreground);font-weight:500}.praxis-list-root mat-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:var(--p-list-expansion-padding, 14px 16px);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75);color:var(--p-list-foreground)}.praxis-list-root[data-item-appearance=card] .list-row-shell--expanded .list-item-content,.praxis-list-root.item-appearance-card .list-row-shell--expanded .list-item-content{border-bottom-left-radius:0;border-bottom-right-radius:0}.praxis-list-root[data-item-appearance=card] .item-expansion--attached,.praxis-list-root.item-appearance-card .item-expansion--attached{margin:0;border-top:0;border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:var(--p-list-radius, 12px);border-bottom-right-radius:var(--p-list-radius, 12px);background:color-mix(in srgb,var(--md-sys-color-surface-container-low, var(--p-list-surface)) 82%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 65%,transparent)}.skin-glass .item-expansion--attached{backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.item-expansion--detached,.item-expansion--modal{margin-top:var(--p-list-item-stack-gap);background:var(--md-sys-color-surface-container, var(--p-list-surface));box-shadow:var(--md-sys-elevation-level1)}.item-expansion--modal{border-color:var(--md-sys-color-outline);box-shadow:var(--md-sys-elevation-level3)}.item-expansion-grid{display:grid;grid-template-columns:var(--p-list-expansion-columns, repeat(auto-fit, minmax(220px, 1fr)));gap:var(--p-list-expansion-gap, 16px)}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground)}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted)}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px 16px}.expansion-key-value-row{display:grid;gap:2px;padding:6px 10px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-surface-container-highest, rgba(255, 255, 255, .04)) 45%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 45%,transparent)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0}.expansion-key-value-row dt{font-size:.68rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.85rem;font-weight:600;color:var(--p-list-foreground)}.cards-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, max(300px, var(--p-list-tile-minW)))), 1fr)));gap:max(var(--p-list-tile-gap),16px)}.tiles-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, var(--p-list-tile-minW))), 1fr)));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.tile-main-action{display:flex;flex:1;min-width:0;flex-direction:column;gap:10px;color:inherit;cursor:pointer}.tile-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid,.cards-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:max(var(--p-list-tile-padding),16px);display:flex;flex-direction:column;gap:var(--p-list-item-gap);min-height:var(--p-list-card-minH, 220px);position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.density-compact .item-card{min-height:var(--p-list-card-minH, 148px)}.pdx-list-item--primary{--p-list-item-rule-tone: var(--md-sys-color-primary, #06b6d4);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 52%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--success{--p-list-item-rule-tone: var(--p-color-success, #10b981);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 48%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--warning{--p-list-item-rule-tone: var( --p-color-warning, var(--md-sys-color-tertiary, #f59e0b) );border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 54%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 10%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--danger{--p-list-item-rule-tone: var(--md-sys-color-error, #ef4444);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 56%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 11%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--muted{opacity:.78;border-style:dashed!important;background:color-mix(in srgb,var(--md-sys-color-surface-variant) 34%,var(--p-list-surface))!important}.pdx-list-item--neutral{border-color:var(--md-sys-color-outline-variant)!important;background:var(--p-list-surface)!important}.card-main-action{display:block;width:100%;min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.card-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.item-card .list-item-content{display:block;padding:0;min-width:0;overflow:hidden}.item-card .list-item-leading{position:absolute;top:18px;left:18px;min-height:0;z-index:1}.item-card .leading-placeholder{width:36px;height:36px}.item-card .leading-icon.mat-icon,.item-card .list-item-leading>mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent));color:var(--md-sys-color-primary)}.item-card .list-item-text{display:grid;gap:9px;padding-left:50px;width:100%;min-width:0;box-sizing:border-box}.item-card .primary{padding-right:min(50%,160px);font-size:1rem;font-weight:800;letter-spacing:-.01em;line-height:1.18;min-width:0;overflow-wrap:anywhere}.item-card .secondary{color:var(--p-list-foreground-muted);font-weight:600;line-height:1.35;min-width:0;overflow-wrap:anywhere}.item-card .features{display:flex;flex-direction:column;gap:8px;margin-top:2px}.item-card .feature{display:inline-flex;align-items:start;gap:8px;min-width:0;max-width:100%;overflow-wrap:anywhere}.item-card .feature mat-icon{margin-top:1px;color:var(--p-list-foreground-muted);opacity:.86}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width);grid-column:1/-1;align-items:stretch;padding-right:0}.card-detail-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:10px;margin-top:16px}.card-detail{min-width:0;padding:11px 12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 22%,transparent),color-mix(in srgb,var(--p-list-surface) 92%,transparent));box-shadow:inset 0 1px #ffffff14}.card-detail__label{display:block;margin-bottom:3px;color:var(--p-list-foreground-muted);font-size:.68rem;font-weight:700;letter-spacing:.08em;line-height:1.1;text-transform:uppercase}.card-detail__value{display:block;min-width:0;color:var(--p-list-foreground);font-size:.94rem;font-weight:800;line-height:1.2;overflow-wrap:normal;word-break:normal}.card-detail__value,.card-detail__value *{white-space:nowrap}.card-detail--balance .card-detail__value{color:var(--md-sys-color-primary)}.card-detail--limit .card-detail__value{color:var(--md-sys-color-error)}.card-detail--risk .card-detail__value{color:var(--md-sys-color-tertiary, var(--p-list-foreground))}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);margin-top:auto}.status-overlay{position:absolute;top:14px;right:14px;max-width:min(42%,148px);overflow:hidden;pointer-events:none}.status-overlay .mat-mdc-chip{pointer-events:auto;width:100%;min-width:0;max-width:100%}.status-overlay .mdc-evolution-chip__text-label,.status-overlay .mat-mdc-chip-action-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.leading-icon.mat-icon,.list-item-leading>mat-icon,.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon],[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon]{width:36px;height:36px;min-width:36px;line-height:36px;font-size:19px;display:inline-flex;align-items:center;justify-content:center;border-radius:10px;box-sizing:border-box;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 15%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 30%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary));box-shadow:inset 0 1px #ffffff0f}.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon,[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon{font-size:19px;width:19px;height:19px;line-height:19px;color:inherit}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);--mdc-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mat-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mdc-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mat-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mdc-chip-outline-color: var(--p-list-chip-border-color, transparent);--mat-chip-outline-color: var(--p-list-chip-border-color, transparent);font-size:var(--p-list-chip-font-size);font-weight:600;letter-spacing:.02em;border-radius:999px!important;background-color:var(--p-list-chip-background, var(--md-sys-color-surface-container-high))!important;color:var(--p-list-chip-color, var(--md-sys-color-on-surface))!important;border:1px solid var(--p-list-chip-border-color, transparent)!important}:host ::ng-deep .mat-mdc-chip .mdc-evolution-chip__text-label,:host ::ng-deep .mat-mdc-chip .mat-mdc-chip-action-label{color:var(--p-list-chip-color, inherit)!important;font-weight:600;font-size:.72rem;letter-spacing:.02em}.meta .mat-icon{font-size:18px;height:18px;width:18px}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important;color:var(--p-list-chip-color, currentColor)!important}.w-60{width:60%}.w-40{width:40%}.list-collection-toolbar{display:flex;align-items:center;gap:12px;padding:12px;margin-bottom:8px;color:var(--p-list-foreground);background:var(--p-list-surface-low);border:var(--p-list-border);border-radius:calc(var(--p-list-radius) * .75)}.list-toolbar-search{flex:1 1 320px;min-width:220px;max-width:440px}.list-toolbar-commands{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-inline-start:auto}.list-toolbar-commands button{border-radius:8px}.list-toolbar-commands button .mat-icon{margin-right:6px}.list-toolbar-sort{width:200px}.list-remote-error{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;margin:8px 4px 0;padding:16px;color:var(--md-sys-color-on-error-container);background:var(--md-sys-color-error-container);border-radius:calc(var(--p-list-radius) * .75)}.list-remote-error__copy{display:flex;flex-direction:column;gap:4px;min-width:0}.list-remote-error__copy span{color:color-mix(in srgb,var(--md-sys-color-on-error-container) 82%,transparent);line-height:1.45}.list-remote-error button{color:var(--md-sys-color-on-error-container);--mat-button-outlined-label-text-color: var( --md-sys-color-on-error-container );--mat-button-outlined-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent );--mdc-outlined-button-label-text-color: var( --md-sys-color-on-error-container );--mdc-outlined-button-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent )}.mat-mdc-paginator{margin-top:14px;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--p-list-surface-low);color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-container{min-height:40px;padding:4px 8px;gap:6px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select{margin-left:8px;width:92px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-text-field-wrapper{--mdc-outlined-text-field-container-color: color-mix( in srgb, var(--p-list-surface-low) 92%, var(--md-sys-color-on-surface) 8% );--mdc-outlined-text-field-input-text-color: var(--p-list-foreground);min-height:40px;padding-inline:12px 8px;background:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;background-color:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;color:var(--p-list-foreground)!important}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-form-field-infix{min-height:40px;padding-block:8px;width:auto}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-select-trigger{min-height:24px;padding-right:2px;color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-range-label,:host ::ng-deep .mat-mdc-paginator .mat-mdc-select-value-text{font-size:12px;color:var(--p-list-foreground-muted)}.list-paginator-total{margin-top:14px;padding:4px 8px 0;font-size:12px;color:var(--p-list-foreground-muted)}:host ::ng-deep .mat-mdc-paginator.hide-range .mat-mdc-paginator-range-label{display:none}::ng-deep .praxis-list-paginator-select-panel.mat-mdc-select-panel{--mat-select-panel-background-color: var( --md-sys-color-surface-container, var(--mat-sys-surface-container) );background:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;background-color:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 70%,transparent);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, #000) 28%,transparent)}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option{--mat-option-label-text-color: var(--md-sys-color-on-surface, #111827);color:var(--md-sys-color-on-surface, #111827)!important}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled),::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option.mat-mdc-option-active{--mat-option-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-primary, #2f7cff) 14%, transparent );background:color-mix(in srgb,var(--md-sys-color-primary, #2f7cff) 14%,transparent)!important;color:var(--md-sys-color-on-surface, #111827)!important}.muted{color:var(--p-list-foreground-muted)}@container (max-width: 720px){.executive-inline-skin .list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.executive-inline-skin .list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--primary,.executive-inline-skin .list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.executive-inline-skin .list-item-content--row-layout .list-row-slot--meta,.executive-inline-skin .list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.executive-inline-skin .list-selection-control{padding-left:0}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.executive-inline-skin .list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.executive-inline-skin .list-item-trailing .list-item-actions{margin-inline-start:auto}.executive-inline-skin .item-expansion{margin-left:0;margin-right:0}.executive-inline-skin .list-collection-toolbar{flex-direction:column;align-items:stretch}.executive-inline-skin .list-toolbar-search,.executive-inline-skin .list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.executive-inline-skin .list-toolbar-commands{width:100%;margin-inline-start:0}.executive-inline-skin .list-toolbar-sort{flex:1 1 100%}.executive-inline-skin .list-toolbar-commands button{flex:0 0 auto}.executive-inline-skin .list-remote-error{grid-template-columns:auto minmax(0,1fr)}.executive-inline-skin .list-remote-error button{grid-column:1/-1;justify-self:stretch}}@container (max-width: 420px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}@media(max-width:640px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}.list-loading-status{display:flex;align-items:center;gap:8px;padding:12px 0;color:inherit;--mat-progress-spinner-active-indicator-color: currentColor}.list-loading-status:empty{display:none}.praxis-list-virtual-viewport,.praxis-list-bounded-viewport{display:block;width:100%;overflow-y:auto;outline:none;padding-right:4px;box-sizing:border-box;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent) transparent}.praxis-list-virtual-viewport::-webkit-scrollbar,.praxis-list-bounded-viewport::-webkit-scrollbar{width:6px;height:6px}.praxis-list-virtual-viewport::-webkit-scrollbar-track,.praxis-list-bounded-viewport::-webkit-scrollbar-track{background:transparent}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent);border-radius:999px}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb:hover,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--md-sys-color-on-surface-variant, #94a3b8) 72%,transparent)}.praxis-list-virtual-viewport{height:var(--p-list-viewport-height, 400px);contain:strict}.praxis-list-virtual-viewport .praxis-list-virtual-list{padding-top:0;padding-bottom:0}.list-item-menu-trigger{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--md-sys-shape-corner-full, 9999px);color:var(--p-list-foreground-muted, inherit);transition:background-color .15s ease,color .15s ease}.list-item-menu-trigger:hover{background-color:var(--p-list-item-hover-surface, rgba(0, 0, 0, .04));color:var(--p-list-foreground, inherit)}\n"] }]
|
|
13396
|
+
], template: "<div class=\"list-loading-status\" role=\"status\">\n @if (loading$ | async) {\n <mat-progress-spinner mode=\"indeterminate\" diameter=\"20\" aria-hidden=\"true\"></mat-progress-spinner>\n <span>{{ t('loading', 'Carregando itens\u2026') }}</span>\n }\n</div>\n<div\n class=\"praxis-list-root\"\n tabindex=\"-1\"\n [attr.aria-busy]=\"(loading$ | async) ? 'true' : 'false'\"\n [ngClass]=\"skinClasses\"\n [attr.data-skin-scope]=\"skinScopeId\"\n [attr.data-item-appearance]=\"config?.layout?.itemAppearance || null\"\n [attr.aria-label]=\"config.a11y?.ariaLabel || null\"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n>\n @if (enableCustomization) {\n <div class=\"list-assistant\">\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openConfigEditor()\"\n [matTooltip]=\"configEditorLabel()\"\n [attr.aria-label]=\"configEditorLabel()\"\n data-testid=\"praxis-list-open-config-editor\"\n >\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n <button\n mat-mini-fab\n type=\"button\"\n color=\"primary\"\n (click)=\"openAiAssistant()\"\n matTooltip=\"Copiloto semantico Praxis\"\n aria-label=\"Abrir copiloto semantico Praxis da lista\"\n data-testid=\"praxis-list-ai-assistant-trigger\"\n >\n <mat-icon [praxisIcon]=\"'auto_awesome'\"></mat-icon>\n </button>\n </div>\n }\n\n @if (aiAssistantOpen && aiAssistantViewState) {\n <praxis-ai-assistant-shell\n [labels]=\"aiAssistantLabels\"\n [mode]=\"aiAssistantViewState.mode\"\n [state]=\"aiAssistantViewState.state\"\n [contextItems]=\"aiAssistantViewState.contextItems\"\n [attachments]=\"aiAssistantViewState.attachments\"\n [messages]=\"aiAssistantViewState.messages\"\n [quickReplies]=\"aiAssistantViewState.quickReplies\"\n [prompt]=\"aiAssistantPrompt\"\n [statusText]=\"aiAssistantViewState.statusText\"\n [errorText]=\"aiAssistantViewState.errorText\"\n [busy]=\"\n aiAssistantViewState.state === 'processing' ||\n aiAssistantViewState.state === 'applying'\n \"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"praxis-list-ai-assistant\"\n panelTestId=\"praxis-list-ai-assistant-panel\"\n submitTestId=\"praxis-list-ai-assistant-submit\"\n applyTestId=\"praxis-list-ai-assistant-apply\"\n (promptChange)=\"onAiAssistantPromptChange($event)\"\n (submitPrompt)=\"onAiAssistantSubmit($event)\"\n (apply)=\"onAiAssistantApply()\"\n (retryTurn)=\"onAiAssistantRetry()\"\n (cancelTurn)=\"onAiAssistantCancel()\"\n (quickReply)=\"onAiAssistantQuickReply($event)\"\n (editMessage)=\"onAiAssistantEditMessage($event)\"\n (resendMessage)=\"onAiAssistantResendMessage($event)\"\n (layoutChange)=\"onAiAssistantLayoutChange($event)\"\n (close)=\"closeAiAssistant()\"\n ></praxis-ai-assistant-shell>\n }\n\n @if (\n config.export?.enabled ||\n (isRemoteDataMode() &&\n (config.ui?.showSort ||\n (config.ui?.showSearch && config.ui?.searchField)))\n ) {\n <div\n class=\"list-collection-toolbar\"\n role=\"group\"\n [attr.aria-label]=\"t('toolbar.label', 'Controles da lista')\"\n >\n @if (\n isRemoteDataMode() && config.ui?.showSearch && config.ui?.searchField\n ) {\n <mat-form-field\n class=\"list-toolbar-search\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{\n config.ui?.searchPlaceholder || t(\"toolbar.search\", \"Buscar\")\n }}</mat-label>\n <mat-icon matPrefix [praxisIcon]=\"'search'\"></mat-icon>\n <input\n #searchInput\n matInput\n type=\"search\"\n (input)=\"onSearchInput($any($event.target).value)\"\n />\n </mat-form-field>\n }\n\n <div class=\"list-toolbar-commands\">\n @if (isRemoteDataMode() && config.ui?.showSort) {\n <mat-form-field\n class=\"list-toolbar-sort\"\n appearance=\"outline\"\n subscriptSizing=\"dynamic\"\n >\n <mat-label>{{ t(\"toolbar.sort\", \"Ordenar por\") }}</mat-label>\n @let activeSort = activeSortValue((page$ | async)?.sort);\n <mat-select\n [value]=\"activeSort\"\n (selectionChange)=\"onSortChange($event.value)\"\n >\n @if (activeSort && !hasSortOption(activeSort)) {\n <mat-option [value]=\"activeSort\">{{ activeSort }}</mat-option>\n }\n @for (op of config.ui?.sortOptions || []; track $index) {\n <mat-option [value]=\"sortOptionValue(op)\">{{\n sortOptionLabel(op)\n }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @if (config.export?.enabled) {\n <button\n mat-stroked-button\n type=\"button\"\n [matMenuTriggerFor]=\"listExportMenu\"\n [attr.aria-label]=\"t('export.button', 'Exportar')\"\n [disabled]=\"exportBusy\"\n [attr.aria-busy]=\"exportBusy\"\n >\n <mat-icon [praxisIcon]=\"'download'\"></mat-icon>\n {{ t(\"export.button\", \"Exportar\") }}\n </button>\n <span class=\"cdk-visually-hidden\" aria-live=\"polite\">\n {{ exportStatusMessage }}\n </span>\n <mat-menu #listExportMenu=\"matMenu\">\n @for (format of listExportFormats(); track format) {\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"onExportAction(format)\"\n >\n <mat-icon [praxisIcon]=\"exportIcon(format)\"></mat-icon>\n {{ format.toUpperCase() }}\n </button>\n }\n </mat-menu>\n }\n </div>\n </div>\n }\n\n <!-- Skeleton while loading -->\n @if (loading$ | async) {\n @if (hasSkeleton()) {\n @if (isListVariant()) {\n <mat-list>\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <mat-list-item>\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </mat-list-item>\n }\n </mat-list>\n } @else {\n <div class=\"cards-grid\">\n @for (_ of skeletonItems(); track $index; let i = $index) {\n <div class=\"item-card\">\n <div class=\"list-item-content\">\n <div class=\"list-item-leading\">\n <div class=\"skeleton skeleton-avatar\"></div>\n </div>\n <div class=\"list-item-text\">\n <div class=\"skeleton skeleton-line w-60\"></div>\n @if (layoutLines > 1) {\n <div class=\"skeleton skeleton-line w-40\"></div>\n }\n </div>\n <div class=\"list-item-trailing\">\n <div class=\"skeleton skeleton-chip\"></div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n }\n } @else {\n <ng-container *ngTemplateOutlet=\"notLoading\"></ng-container>\n }\n\n <ng-template #notLoading>\n @if (error$ | async; as remoteError) {\n <div class=\"list-remote-error\" role=\"alert\">\n <mat-icon [praxisIcon]=\"'error_outline'\"></mat-icon>\n <div class=\"list-remote-error__copy\">\n <strong>{{\n t(\"remoteError.title\", \"N\u00E3o foi poss\u00EDvel carregar a lista\")\n }}</strong>\n <span>\n {{\n remoteError.filtered\n ? t(\n \"remoteError.filteredDescription\",\n \"Os filtros permanecem aplicados. Nenhum dado sem filtro foi exibido.\"\n )\n : t(\n \"remoteError.description\",\n \"Verifique a conex\u00E3o e tente novamente.\"\n )\n }}\n </span>\n </div>\n <button mat-stroked-button type=\"button\" (click)=\"retryRemoteData()\">\n {{ t(\"remoteError.retry\", \"Tentar novamente\") }}\n </button>\n </div>\n }\n\n <!-- Empty state -->\n @if (items$ | async; as all) {\n @if (all.length === 0 && !(error$ | async)) {\n @if (hasCustomEmptyStateTemplate()) {\n <div\n class=\"section-header\"\n [class.section-header--setup]=\"isResourceConnectionMissing()\"\n >\n @if (emptyStateTemplate(); as empty) {\n @if (\n simpleRichContentNodes(empty, {\n imageAlt: config.templating?.emptyState?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (empty.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"empty.value\"\n [ngClass]=\"empty.class\"\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [style.cssText]=\"\n (empty.style ? empty.style + ';' : '') +\n iconStyle(empty.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n >\n <img\n [src]=\"empty.value\"\n [alt]=\"config.templating?.emptyState?.imageAlt || ''\"\n />\n @if (empty.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(empty.badge?.color)\n ? empty.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (empty.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(empty.badge?.color, empty.badge?.variant)\n \"\n >{{ empty.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(empty.color) ? empty.color : undefined\n \"\n [ngClass]=\"[\n empty.class || '',\n (empty.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(empty.color, empty.variant) +\n (empty.style ? ';' + empty.style : '')\n \"\n >{{ empty.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">\n @for (\n _ of ratingRange(empty);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, empty.value)\"\n [color]=\"ratingThemeColor(empty)\"\n [style.cssText]=\"ratingIconStyle(empty)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"empty.class\"\n [style.cssText]=\"empty.style\"\n [innerHTML]=\"empty.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"empty\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"empty\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"empty\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"empty.class\" [style.cssText]=\"empty.style\">{{\n empty.value\n }}</span>\n }\n }\n }\n }\n </div>\n } @else {\n <praxis-empty-state-card\n class=\"section-header\"\n [class.section-header--setup]=\"isResourceConnectionMissing()\"\n [icon]=\"emptyStateIcon()\"\n [title]=\"emptyStateTitle()\"\n [description]=\"emptyStateDescription()\"\n [primaryAction]=\"emptyStatePrimaryAction()\"\n [secondaryActions]=\"emptyStateSecondaryActions()\"\n />\n }\n }\n }\n\n <ng-template\n #rowLayoutNode\n let-node\n let-slot=\"slot\"\n let-imageAlt=\"imageAlt\"\n >\n @if (\n simpleRichContentNodes(node, { slot: slot, imageAlt: imageAlt });\n as richNodes\n ) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"richNodes\"></praxis-rich-content>\n } @else {\n @switch (node?.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"node?.value\"\n [ngClass]=\"[\n slot === 'leading' ? 'leading-icon' : '',\n node?.class || '',\n ]\"\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [style.cssText]=\"\n slot === 'leading'\n ? leadingIconStyle(node?.color, node?.style)\n : (node?.style || '' ? node.style + ';' : '') +\n iconStyle(node?.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n >\n <img\n [src]=\"node?.value\"\n [alt]=\"node?.imageAlt || imageAlt || ''\"\n />\n @if (node?.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(node?.badge?.color)\n ? node?.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (node?.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(node?.badge?.color, node?.badge?.variant)\n \"\n >\n {{ node?.badge?.value }}\n </mat-chip>\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"isThemeColor(node?.color) ? node?.color : undefined\"\n [ngClass]=\"[\n node?.class || '',\n (node?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(node?.color, node?.variant) +\n (node?.style ? ';' + node.style : '')\n \"\n >\n {{ node?.value }}\n </mat-chip>\n }\n @case (\"rating\") {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @for (_ of ratingRange(node); track $index; let idx = $index) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, node?.value)\"\n [color]=\"ratingThemeColor(node)\"\n [style.cssText]=\"ratingIconStyle(node)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"node?.class\"\n [style.cssText]=\"node?.style\"\n [innerHTML]=\"node?.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"node\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose [compose]=\"node\"></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"node\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"node?.class\" [style.cssText]=\"node?.style\">\n @if (\n slot === \"meta\" && config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ node?.value }}\n </span>\n }\n }\n }\n </ng-template>\n\n <ng-template #featureContent let-item let-feature=\"feature\">\n @if (featureTemplateNode(item, feature); as featureNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: featureNode,\n slot: 'feature',\n imageAlt: feature?.imageAlt || '',\n }\n \"\n ></ng-container>\n } @else if (featureRichContentNodes(item, feature); as featureNodes) {\n <praxis-rich-content layout=\"inline\" [nodes]=\"featureNodes\"></praxis-rich-content>\n } @else {\n @if (feature.icon && featuresMode() !== \"labels-only\") {\n <mat-icon [praxisIcon]=\"feature.icon\"></mat-icon>\n }\n @if (featuresMode() !== \"icons-only\") {\n <span [ngClass]=\"feature.class\" [style.cssText]=\"feature.style\">\n @for (line of featureLabelLines(item, feature.expr); track $index) {\n <span class=\"feature-line\">{{ line }}</span>\n }\n </span>\n }\n }\n @if (\n featureProgressPercent(item, feature.expr, feature.class);\n as progress\n ) {\n <span class=\"feature-progress\" aria-hidden=\"true\">\n <span\n class=\"feature-progress__value\"\n [style.width.%]=\"progress\"\n ></span>\n </span>\n }\n </ng-template>\n\n <ng-template\n #listRowLayout\n let-item\n let-index=\"index\"\n let-sectionKey=\"sectionKey\"\n let-clickable=\"clickable\"\n >\n <div\n class=\"list-item-content\"\n [ngClass]=\"rowLayoutItemClass(item)\"\n [attr.style]=\"rowLayoutItemStyle(item)\"\n >\n @if (clickable) {\n <button\n type=\"button\"\n class=\"list-row-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, index) : null\n \"\n (click)=\"onRowActivate(item, index, sectionKey)\"\n ></button>\n }\n @for (\n column of rowLayoutColumns();\n track rowLayoutTrackColumn($index, column)\n ) {\n <div\n [attr.data-row-slot]=\"column.slot\"\n [ngClass]=\"rowLayoutColumnClass(column)\"\n [attr.style]=\"rowLayoutColumnStyle(column)\"\n >\n @if (column.slot === \"leading\") {\n @if (rowLayoutSlot(item, column.slot); as lead) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: lead,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n } @else if (column.slot === \"trailing\") {\n @if (rowLayoutSlot(item, column.slot); as trailingNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: trailingNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"rowActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #rowActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, index)\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n } @else if (column.slot === \"actions\") {\n @if ((visibleActions(item, \"actions\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"actions\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, index)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, item, index)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"\n onActionClick($event, action.id, item, index)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, item, index)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n index\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, index)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n } @else if (column.slot === \"expand\") {\n @if (showExpandIcon(\"expand\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, index) ? 'expand_less' : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, index)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon() ? isExpanded(item, index) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon() ? expandRegionId(item, index) : null\n \"\n (click)=\"onExpandToggle($event, item, index)\"\n ></button>\n }\n } @else if (rowLayoutSlot(item, column.slot); as slotNode) {\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: slotNode,\n slot: column.slot,\n imageAlt: rowLayoutImageAlt(column.slot),\n }\n \"\n ></ng-container>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- List variant -->\n @if (isListVariant()) {\n <!-- Selection and row actions share one neutral list shell so every\n interactive affordance remains a sibling keyboard target. -->\n <ng-container *ngTemplateOutlet=\"readList\"></ng-container>\n\n <!-- Unified list surface -->\n <ng-template #readList>\n @if (isVirtualScrollEnabled()) {\n <cdk-virtual-scroll-viewport\n class=\"praxis-list-virtual-viewport\"\n [itemSize]=\"virtualScrollItemSize()\"\n [minBufferPx]=\"virtualScrollMinBufferPx()\"\n [maxBufferPx]=\"virtualScrollMaxBufferPx()\"\n [style.height]=\"virtualScrollViewportHeight()\"\n >\n <mat-list\n class=\"praxis-list-virtual-list\"\n role=\"list\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n <mat-list-item\n *cdkVirtualFor=\"\n let item of virtualScrollItems(sections$ | async, items$ | async);\n let i = index;\n trackBy: trackByVirtualItem\n \"\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n </mat-list>\n </cdk-virtual-scroll-viewport>\n } @else {\n <mat-list\n role=\"list\"\n [class.praxis-list-bounded-viewport]=\"hasBoundedScrollViewport()\"\n [style.max-height]=\"hasBoundedScrollViewport() ? virtualScrollViewportHeight() : null\"\n [attr.aria-label]=\"\n isSelectionEnabled()\n ? selectionListAriaLabel()\n : config.a11y?.ariaLabel || null\n \"\n [attr.aria-labelledby]=\"config.a11y?.ariaLabelledBy || null\"\n >\n @for (\n section of sections$ | async;\n track trackBySection($index, section);\n let sidx = $index\n ) {\n @if (section.key) {\n <div class=\"section-header mat-subheader\">\n @if (sectionHeaderTemplate(section.key); as sh) {\n @if (\n simpleRichContentNodes(sh, {\n imageAlt:\n config.templating?.sectionHeader?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (sh.type) {\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"sh.value\"\n [ngClass]=\"sh.class\"\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [style.cssText]=\"\n (sh.style ? sh.style + ';' : '') +\n iconStyle(sh.color)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <span\n class=\"inline-image\"\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n >\n <img\n [src]=\"sh.value\"\n [alt]=\"\n config.templating?.sectionHeader?.imageAlt || ''\n \"\n />\n @if (sh.badge?.value) {\n <mat-chip\n class=\"inline-badge\"\n [color]=\"\n isThemeColor(sh.badge?.color)\n ? sh.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (sh.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(sh.badge?.color, sh.badge?.variant)\n \"\n >{{ sh.badge?.value }}</mat-chip\n >\n }\n </span>\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(sh.color) ? sh.color : undefined\n \"\n [ngClass]=\"[\n sh.class || '',\n (sh.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : '',\n ]\"\n [style.cssText]=\"\n chipStyle(sh.color, sh.variant) +\n (sh.style ? ';' + sh.style : '')\n \"\n >{{ sh.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">\n @for (\n _ of ratingRange(sh);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, sh.value)\"\n [color]=\"ratingThemeColor(sh)\"\n [style.cssText]=\"ratingIconStyle(sh)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"sh.class\"\n [style.cssText]=\"sh.style\"\n [innerHTML]=\"sh.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"sh\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"sh\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"sh\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span [ngClass]=\"sh.class\" [style.cssText]=\"sh.style\">{{\n sh.value\n }}</span>\n }\n }\n }\n }\n </div>\n }\n @for (\n item of section.items;\n track trackByItem($index, item);\n let i = $index\n ) {\n <mat-list-item\n role=\"listitem\"\n [attr.data-item-status]=\"item?.status || null\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n listItemBody;\n context: {\n $implicit: item,\n index: i,\n sectionKey: section.key || undefined,\n }\n \"\n ></ng-container>\n </mat-list-item>\n @if (\n (config.layout?.dividers === \"all\" ||\n config.layout?.dividers === \"between\") &&\n i < section.items.length - 1\n ) {\n <mat-divider\n role=\"presentation\"\n aria-hidden=\"true\"\n ></mat-divider>\n }\n }\n }\n </mat-list>\n }\n </ng-template>\n\n <ng-template #listItemBody let-item let-i=\"index\" let-sectionKey=\"sectionKey\">\n <div\n class=\"list-row-shell\"\n [class.list-row-shell--selectable]=\"isSelectionEnabled()\"\n [class.list-row-shell--with-control]=\"shouldShowSelectionControl()\"\n [class.list-row-shell--selected]=\"isItemSelected(item)\"\n [class.list-row-shell--expanded]=\"isExpandable() && isExpanded(item, i)\"\n >\n @if (hasRowLayoutGrid()) {\n <ng-container\n *ngTemplateOutlet=\"\n listRowLayout;\n context: {\n $implicit: item,\n index: i,\n sectionKey: sectionKey,\n clickable: true,\n }\n \"\n ></ng-container>\n } @else {\n <div\n class=\"list-item-content\"\n [ngClass]=\"itemRuleClass(item)\"\n [attr.style]=\"itemRuleStyle(item)\"\n >\n <button\n type=\"button\"\n class=\"list-item-main-action\"\n [attr.aria-label]=\"itemAriaLabel(item)\"\n [attr.aria-expanded]=\"\n expansionOwnedByRow() ? isExpanded(item, i) : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByRow() ? expandRegionId(item, i) : null\n \"\n (click)=\"\n onRowActivate(item, i, sectionKey)\n \"\n >\n <div class=\"list-item-leading\">\n @if (leading(item); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt:\n config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"\n config.templating?.leading?.imageAlt ||\n ''\n \"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color)\n ? lead.color\n : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(lead.color, lead.variant)\n \"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(item)?.class\"\n [style.cssText]=\"primary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(primary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(item)\"\n ></praxis-list-metric>\n } @else if (primary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(item)\"\n ></praxis-list-compose>\n } @else if (primary(item)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(item)\"\n ></praxis-list-runtime-component>\n } @else if (primary(item)?.type === \"html\") {\n <span [innerHTML]=\"primary(item)?.value\"></span>\n } @else {\n {{ primary(item)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(item)?.class\"\n [style.cssText]=\"secondary(item)?.style\"\n >\n @if (\n simpleRichContentNodes(secondary(item));\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (\n item.segmentVariant &&\n item.segmentLabel &&\n item.accountType &&\n item.since\n ) {\n <!-- Component-based rendering for executive items -->\n <span class=\"exec-subline\">\n <praxis-executive-badge\n [variant]=\"item.segmentVariant\"\n [label]=\"item.segmentLabel\"\n ></praxis-executive-badge>\n <span class=\"exec-subcopy\">{{\n item.accountType\n }}</span>\n <span class=\"exec-subseparator\">\u00B7</span>\n <span class=\"exec-subcopy\"\n >Desde {{ item.since }}</span\n >\n </span>\n } @else if (secondary(item)?.type === \"html\") {\n <span\n [innerHTML]=\"secondary(item)?.value\"\n ></span>\n } @else if (secondary(item)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(item)\"\n ></praxis-list-metric>\n } @else if (secondary(item)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(item)\"\n ></praxis-list-compose>\n } @else if (\n secondary(item)?.type === \"component\"\n ) {\n <praxis-list-runtime-component\n [component]=\"secondary(item)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(item)?.value }}\n }\n </div>\n }\n @if (meta(item); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n config.templating?.metaPrefixIcon;\n as mpi\n ) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"\n featureSemanticClass(item, f.expr, f.class)\n \"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: item, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n </div>\n </button>\n <div class=\"list-item-trailing\">\n @if (meta(item); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, { slot: \"meta\" });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(m.color, m.variant)\n \"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color)\n ? m.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"m.value\"\n [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (\n config.templating?.metaPrefixIcon;\n as mpi2\n ) {\n <mat-icon\n [praxisIcon]=\"mpi2\"\n ></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(item); as tr) {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt:\n config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr.color, tr.variant)\n \"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color)\n ? tr.color\n : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt ||\n ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n @if (\n item.alertsData !== undefined &&\n item.ownerName\n ) {\n <!-- Component-based rendering for executive trailing -->\n <span class=\"exec-trailing-shell\">\n <praxis-executive-alerts\n [alerts]=\"item.alertsData\"\n ></praxis-executive-alerts>\n <praxis-executive-owner\n [name]=\"item.ownerName\"\n ></praxis-executive-owner>\n </span>\n } @else {\n <span [innerHTML]=\"tr.value\"></span>\n }\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n @if (showExpandIcon(\"trailing\")) {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n isExpanded(item, i)\n ? 'expand_less'\n : 'expand_more'\n \"\n size=\"compact\"\n class=\"expand-toggle\"\n [attr.aria-label]=\"expandToggleAriaLabel(item, i)\"\n [attr.aria-expanded]=\"\n expansionOwnedByIcon()\n ? isExpanded(item, i)\n : null\n \"\n [attr.aria-controls]=\"\n expansionOwnedByIcon()\n ? expandRegionId(item, i)\n : null\n \"\n (click)=\"onExpandToggle($event, item, i)\"\n ></button>\n }\n @if ((visibleActions(item, \"trailing\") || []).length || (visibleActions(item, \"menu\") || []).length) {\n <div\n class=\"list-item-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(item, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"\n action.icon || 'more_horiz'\n \"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, item, i)\"\n [style.cssText]=\"\n actionIconStyle(action.color)\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'stroked')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'raised')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant ||\n action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color)\n ? action.color\n : undefined\n \"\n [style.cssText]=\"\n buttonStyle(action.color, 'flat')\n \"\n (click)=\"\n onActionClick($event, action.id, item, i)\n \"\n [attr.aria-label]=\"\n action.label || action.id\n \"\n [disabled]=\"\n isActionLoading(action.id, item, i)\n \"\n [ngClass]=\"{\n 'action-loading': isActionLoading(\n action.id,\n item,\n i\n ),\n }\"\n >\n @if (isActionLoading(action.id, item, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n @if ((visibleActions(item, \"menu\") || []).length) {\n <button\n type=\"button\"\n praxisIconButton=\"more_vert\"\n size=\"compact\"\n [matMenuTriggerFor]=\"itemActionsMenu\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n class=\"list-item-menu-trigger\"\n (click)=\"$event.stopPropagation()\"\n ></button>\n <mat-menu #itemActionsMenu=\"matMenu\">\n @for (action of visibleActions(item, \"menu\"); track action?.id ?? $index) {\n <button\n mat-menu-item\n (click)=\"onActionClick($event, action.id, item, i)\"\n [disabled]=\"isActionLoading(action.id, item, i)\"\n >\n @if (action.icon) {\n <mat-icon [praxisIcon]=\"action.icon\"></mat-icon>\n }\n <span>{{ action.label || action.id }}</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n }\n </div>\n </div>\n }\n @if (shouldShowSelectionControl()) {\n <div class=\"list-selection-control\">\n @if (config.selection?.mode === \"multiple\") {\n <mat-checkbox\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, $event.checked)\"\n ></mat-checkbox>\n } @else {\n <mat-radio-button\n [name]=\"selectionControlName()\"\n [checked]=\"isItemSelected(item)\"\n [disabled]=\"boundControl.disabled\"\n [aria-label]=\"selectionControlAriaLabel(item)\"\n (change)=\"setItemSelected(item, true)\"\n ></mat-radio-button>\n }\n </div>\n }\n </div>\n @if (isExpandable() && isExpanded(item, i)) {\n <div\n class=\"item-expansion\"\n [ngClass]=\"expansionRenderingClasses()\"\n [style]=\"expansionRenderingStyle()\"\n [id]=\"expandRegionId(item, i)\"\n role=\"region\"\n [attr.aria-label]=\"expansionRegionAriaLabel(item)\"\n >\n <div class=\"item-expansion-grid\">\n @for (\n expansionSection of expansionSections(item);\n track expansionSection.id\n ) {\n <section\n class=\"expansion-section\"\n [attr.data-section-type]=\"expansionSection.type\"\n >\n @if (expansionSection.title) {\n <div class=\"expansion-section-title\">\n {{ expansionSection.title }}\n </div>\n }\n @if (\n expansionSectionHasContent(\n item,\n expansionSection,\n i\n )\n ) {\n @switch (expansionSection.type) {\n @case (\"chip-list\") {\n <div class=\"expansion-chip-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <mat-chip class=\"expansion-chip\">{{\n expansionItemLabel(expansionEntry)\n }}</mat-chip>\n }\n </div>\n }\n @case (\"timeline\") {\n <div class=\"expansion-timeline\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-timeline-item\">\n <div class=\"expansion-timeline-title\">\n {{\n expansionTimelineTitle(expansionEntry)\n }}\n </div>\n @if (\n expansionTimelineMeta(expansionEntry)\n ) {\n <div class=\"expansion-timeline-meta\">\n {{\n expansionTimelineMeta(\n expansionEntry\n )\n }}\n </div>\n }\n @if (\n expansionTimelineDescription(\n expansionEntry\n )\n ) {\n <div\n class=\"expansion-timeline-description\"\n >\n {{\n expansionTimelineDescription(\n expansionEntry\n )\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n @case (\"key-value\") {\n <dl class=\"expansion-key-value\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-key-value-row\">\n @if (\n expansionKeyValueKey(expansionEntry)\n ) {\n <dt>\n {{\n expansionKeyValueKey(expansionEntry)\n }}\n </dt>\n }\n <dd>\n {{\n expansionKeyValueValue(expansionEntry)\n }}\n </dd>\n </div>\n }\n </dl>\n }\n @case (\"rich-content\") {\n @if (\n expansionRichContentDocument(\n item,\n expansionSection,\n i\n );\n as richExpansionDocument\n ) {\n <praxis-rich-content\n [document]=\"richExpansionDocument\"\n [context]=\"\n expansionRichContentContext(\n item,\n expansionSection,\n i\n )\n \"\n [hostCapabilities]=\"\n expansionRichContentHostCapabilities(\n item,\n expansionSection,\n i\n )\n \"\n rootClassName=\"praxis-list-expansion-rich-content\"\n ></praxis-rich-content>\n }\n }\n @default {\n <div class=\"expansion-info-list\">\n @for (\n expansionEntry of expansionSectionItems(\n item,\n expansionSection,\n i\n );\n track $index\n ) {\n <div class=\"expansion-info-item\">\n <div class=\"expansion-info-title\">\n {{ expansionInfoTitle(expansionEntry) }}\n </div>\n @if (expansionInfoValue(expansionEntry)) {\n <div class=\"expansion-info-value\">\n {{\n expansionInfoValue(expansionEntry)\n }}\n </div>\n }\n </div>\n }\n </div>\n }\n }\n } @else {\n <div class=\"expansion-empty\">\n {{\n expansionSection.emptyLabel ||\n \"Sem dados dispon\u00EDveis\"\n }}\n </div>\n }\n </section>\n }\n </div>\n </div>\n }\n </ng-template>\n } @else if (isTilesVariant()) {\n <ng-container *ngTemplateOutlet=\"tilesVariant\"></ng-container>\n } @else {\n <ng-container *ngTemplateOutlet=\"cardsVariant\"></ng-container>\n }\n\n <!-- Cards variant -->\n <ng-template #cardsVariant>\n <div class=\"cards-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-card\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"list-item-content card-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"list-item-leading\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n slot: \"leading\",\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"icon\") {\n <mat-icon\n class=\"leading-icon\"\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n leadingIconStyle(lead.color, lead.style)\n \"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n @if (lead.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(lead.badge?.color)\n ? lead.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (lead.badge?.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n lead.badge?.color,\n lead.badge?.variant\n )\n \"\n >{{ lead.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n } @else {\n <span class=\"leading-placeholder\"></span>\n }\n </div>\n <div class=\"list-item-text\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n @if (meta(it); as m) {\n @if (\n (config.templating?.metaPlacement === \"line\" &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")) ||\n (layoutLines > 2 &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\"))\n ) {\n <div\n class=\"tertiary\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n {{ m.value }}\n </div>\n }\n }\n @if (featuresVisible()) {\n <div class=\"features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n @if (cardDetailSlots(it); as detailSlots) {\n @if (detailSlots.length) {\n <div class=\"card-detail-strip\">\n @for (detail of detailSlots; track detail.slot) {\n <div\n class=\"card-detail\"\n [ngClass]=\"'card-detail--' + detail.slot\"\n >\n <span class=\"card-detail__label\">{{\n detail.label\n }}</span>\n <span class=\"card-detail__value\">\n <ng-container\n *ngTemplateOutlet=\"\n rowLayoutNode;\n context: {\n $implicit: detail.node,\n slot: detail.slot,\n imageAlt: rowLayoutImageAlt(detail.slot),\n }\n \"\n ></ng-container>\n </span>\n </div>\n }\n </div>\n }\n }\n </div>\n <div class=\"list-item-trailing\">\n @if (meta(it); as m) {\n @if (\n !(\n (config.templating?.metaPlacement === \"line\" ||\n layoutLines > 2) &&\n (m?.type === \"text\" ||\n m?.type === \"date\" ||\n m?.type === \"datetime\" ||\n m?.type === \"relative\" ||\n m?.type === \"currency\")\n )\n ) {\n <div\n class=\"meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"m\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>\n @if (config.templating?.metaPrefixIcon; as mpi2) {\n <mat-icon [praxisIcon]=\"mpi2\"></mat-icon>\n }\n {{ m.value }}</span\n >\n }\n }\n }\n </div>\n }\n }\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"status-overlay\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n } @else {\n <div\n class=\"trailing\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n @if (\n simpleRichContentNodes(tr, {\n imageAlt: config.templating?.trailing?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <div\n class=\"lead-image\"\n [ngClass]=\"tr.class\"\n [style.cssText]=\"tr.style\"\n >\n <img\n [src]=\"tr.value\"\n [alt]=\"\n config.templating?.trailing?.imageAlt || ''\n \"\n />\n @if (tr.badge?.value) {\n <mat-chip\n class=\"lead-badge\"\n [color]=\"\n isThemeColor(tr.badge?.color)\n ? tr.badge?.color\n : undefined\n \"\n [ngClass]=\"\n (tr.badge?.variant || 'filled') ===\n 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(\n tr.badge?.color,\n tr.badge?.variant\n )\n \"\n >{{ tr.badge?.value }}</mat-chip\n >\n }\n </div>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr.value)\"\n [color]=\"ratingThemeColor(tr)\"\n [style.cssText]=\"ratingIconStyle(tr)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n <div\n class=\"card-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Tiles variant -->\n <ng-template #tilesVariant>\n <div class=\"tiles-grid\">\n @for (it of (items$ | async) ?? []; track $index; let i = $index) {\n <div\n class=\"item-tile\"\n [ngClass]=\"itemRuleClass(it)\"\n [attr.style]=\"itemRuleStyle(it)\"\n >\n <div\n class=\"tile-main-action\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"itemAriaLabel(it)\"\n (click)=\"onItemClick(it, i)\"\n (keydown.enter)=\"onItemClick(it, i)\"\n (keydown.space)=\"$event.preventDefault(); onItemClick(it, i)\"\n >\n <div class=\"tile-media\">\n @if (leading(it); as lead) {\n @if (\n simpleRichContentNodes(lead, {\n imageAlt: config.templating?.leading?.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (lead.type) {\n @case (\"image\") {\n <img\n [src]=\"lead.value\"\n [alt]=\"config.templating?.leading?.imageAlt || ''\"\n />\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"lead.value\"\n [ngClass]=\"lead.class\"\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [style.cssText]=\"\n (lead.style ? lead.style + ';' : '') +\n iconStyle(lead.color)\n \"\n ></mat-icon>\n }\n @case (\"text\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(lead.color) ? lead.color : undefined\n \"\n [ngClass]=\"\n (lead.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(lead.color, lead.variant)\"\n >{{ lead.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >\n @for (\n _ of ratingRange(lead);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, lead.value)\"\n [color]=\"ratingThemeColor(lead)\"\n [style.cssText]=\"ratingIconStyle(lead)\"\n ></mat-icon>\n }\n </span>\n }\n @case (\"html\") {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n [innerHTML]=\"lead.value\"\n ></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"lead\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"lead\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"lead\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span\n [ngClass]=\"lead.class\"\n [style.cssText]=\"lead.style\"\n >{{ lead.value }}</span\n >\n }\n }\n }\n }\n </div>\n\n @if (trailing(it); as tr) {\n @if (\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr?.type === \"chip\" || tr?.type === \"icon\")\n ) {\n <div class=\"tile-status\">\n @if (simpleRichContentNodes(tr); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @if (tr?.type === \"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [ngClass]=\"\n (tr.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(tr.color, tr.variant)\"\n >{{ tr.value }}</mat-chip\n >\n }\n @if (tr?.type === \"icon\") {\n <mat-icon\n [praxisIcon]=\"tr.value\"\n [color]=\"\n isThemeColor(tr.color) ? tr.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr.color)\"\n ></mat-icon>\n }\n }\n </div>\n }\n }\n\n <div class=\"tile-body\">\n <div\n class=\"primary\"\n [ngClass]=\"primary(it)?.class\"\n [style.cssText]=\"primary(it)?.style\"\n >\n @if (simpleRichContentNodes(primary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (primary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"primary(it)\"\n ></praxis-list-metric>\n } @else if (primary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"primary(it)\"\n ></praxis-list-compose>\n } @else if (primary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"primary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ primary(it)?.value }}\n }\n </div>\n @if (layoutLines > 1) {\n <div\n class=\"secondary\"\n [ngClass]=\"secondary(it)?.class\"\n [style.cssText]=\"secondary(it)?.style\"\n >\n @if (simpleRichContentNodes(secondary(it)); as richNodes) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else if (secondary(it)?.type === \"metric\") {\n <praxis-list-metric\n [metric]=\"secondary(it)\"\n ></praxis-list-metric>\n } @else if (secondary(it)?.type === \"compose\") {\n <praxis-list-compose\n [compose]=\"secondary(it)\"\n ></praxis-list-compose>\n } @else if (secondary(it)?.type === \"component\") {\n <praxis-list-runtime-component\n [component]=\"secondary(it)\"\n ></praxis-list-runtime-component>\n } @else {\n {{ secondary(it)?.value }}\n }\n </div>\n }\n\n @if (meta(it); as m) {\n <div\n class=\"tile-meta\"\n [ngClass]=\"m.class\"\n [style.cssText]=\"m.style\"\n >\n @if (config.templating?.metaPrefixIcon; as mpi) {\n <mat-icon [praxisIcon]=\"mpi\"></mat-icon>\n }\n @if (\n simpleRichContentNodes(m, {\n slot: \"meta\",\n imageAlt: m.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (m.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [ngClass]=\"\n (m.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"chipStyle(m.color, m.variant)\"\n >{{ m.value }}</mat-chip\n >\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(m);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, m.value)\"\n [color]=\"ratingThemeColor(m)\"\n [style.cssText]=\"ratingIconStyle(m)\"\n ></mat-icon>\n }\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"m.value\"\n [color]=\"\n isThemeColor(m.color) ? m.color : undefined\n \"\n [style.cssText]=\"iconStyle(m.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img [src]=\"m.value\" [alt]=\"m.imageAlt || ''\"\n /></span>\n }\n @case (\"html\") {\n <span [innerHTML]=\"m.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric [metric]=\"m\"></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"m\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"m\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ m.value }}</span>\n }\n }\n }\n </div>\n }\n\n @if (featuresVisible()) {\n <div class=\"tiles-features\">\n @for (\n f of config.templating?.features || [];\n track $index;\n let fi = $index\n ) {\n <span\n class=\"feature\"\n [ngClass]=\"featureSemanticClass(it, f.expr, f.class)\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n featureContent;\n context: { $implicit: it, feature: f }\n \"\n ></ng-container>\n </span>\n }\n </div>\n }\n\n @if (trailing(it); as tr2) {\n @if (\n !(\n (config.templating?.statusPosition || \"inline\") ===\n \"top-right\" &&\n (tr2?.type === \"chip\" || tr2?.type === \"icon\")\n )\n ) {\n <div\n class=\"tile-trailing\"\n [ngClass]=\"tr2.class\"\n [style.cssText]=\"tr2.style\"\n >\n @if (\n simpleRichContentNodes(tr2, {\n imageAlt: tr2.imageAlt || \"\",\n });\n as richNodes\n ) {\n <praxis-rich-content\n layout=\"inline\"\n [nodes]=\"richNodes\"\n ></praxis-rich-content>\n } @else {\n @switch (tr2.type) {\n @case (\"chip\") {\n <mat-chip\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [ngClass]=\"\n (tr2.variant || 'filled') === 'outlined'\n ? 'chip-outlined'\n : ''\n \"\n [style.cssText]=\"\n chipStyle(tr2.color, tr2.variant)\n \"\n >{{ tr2.value }}</mat-chip\n >\n }\n @case (\"icon\") {\n <mat-icon\n [praxisIcon]=\"tr2.value\"\n [color]=\"\n isThemeColor(tr2.color) ? tr2.color : undefined\n \"\n [style.cssText]=\"iconStyle(tr2.color)\"\n ></mat-icon>\n }\n @case (\"image\") {\n <span class=\"inline-image\"\n ><img\n [src]=\"tr2.value\"\n [alt]=\"tr2.imageAlt || ''\"\n /></span>\n }\n @case (\"rating\") {\n @for (\n _ of ratingRange(tr2);\n track $index;\n let idx = $index\n ) {\n <mat-icon\n [praxisIcon]=\"starIcon(idx, tr2.value)\"\n [color]=\"ratingThemeColor(tr2)\"\n [style.cssText]=\"ratingIconStyle(tr2)\"\n ></mat-icon>\n }\n }\n @case (\"html\") {\n <span [innerHTML]=\"tr2.value\"></span>\n }\n @case (\"metric\") {\n <praxis-list-metric\n [metric]=\"tr2\"\n ></praxis-list-metric>\n }\n @case (\"compose\") {\n <praxis-list-compose\n [compose]=\"tr2\"\n ></praxis-list-compose>\n }\n @case (\"component\") {\n <praxis-list-runtime-component\n [component]=\"tr2\"\n ></praxis-list-runtime-component>\n }\n @default {\n <span>{{ tr2.value }}</span>\n }\n }\n }\n </div>\n }\n }\n </div>\n </div>\n\n @if ((visibleActions(it, \"trailing\") || []).length) {\n <div\n class=\"tile-actions\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"onActionKeydown($event)\"\n (keydown.space)=\"onActionKeydown($event)\"\n >\n @for (\n action of visibleActions(it, \"trailing\");\n let aidx = $index;\n track action?.id ?? $index\n ) {\n @if ((action.kind || \"icon\") === \"icon\") {\n <button\n type=\"button\"\n [praxisIconButton]=\"action.icon || 'more_horiz'\"\n size=\"compact\"\n [busy]=\"isActionLoading(action.id, it, i)\"\n [style.cssText]=\"actionIconStyle(action.color)\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n ></button>\n } @else {\n @if (action.buttonVariant === \"stroked\") {\n <button\n mat-stroked-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'stroked')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (action.buttonVariant === \"raised\") {\n <button\n mat-raised-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'raised')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n @if (\n !action.buttonVariant || action.buttonVariant === \"flat\"\n ) {\n <button\n mat-flat-button\n [color]=\"\n isThemeColor(action.color) ? action.color : undefined\n \"\n [style.cssText]=\"buttonStyle(action.color, 'flat')\"\n (click)=\"onActionClick($event, action.id, it, i)\"\n [attr.aria-label]=\"action.label || action.id\"\n [disabled]=\"isActionLoading(action.id, it, i)\"\n [ngClass]=\"{\n 'action-loading': isActionLoading(action.id, it, i),\n }\"\n >\n @if (isActionLoading(action.id, it, i)) {\n <mat-progress-spinner\n class=\"action-spinner\"\n mode=\"indeterminate\"\n diameter=\"16\"\n strokeWidth=\"3\"\n ></mat-progress-spinner>\n } @else {\n {{ action.label || action.id }}\n }\n </button>\n }\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </ng-template>\n\n <!-- Remote pagination stays attached to the collection footer. -->\n @if (isRemoteDataMode() && !(error$ | async)) {\n @if (page$ | async; as ps) {\n @if (total$ | async; as total) {\n @if (config.ui?.showRange === false) {\n <div class=\"list-paginator-total\" aria-live=\"polite\">\n {{ remoteTotalLabel(total) }}\n </div>\n }\n <mat-paginator\n [length]=\"total || 0\"\n [pageIndex]=\"ps.pageNumber || 0\"\n [pageSize]=\"ps.pageSize || config.layout?.pageSize || 10\"\n [pageSizeOptions]=\"listPageSizeOptions()\"\n [selectConfig]=\"paginatorSelectConfig\"\n [showFirstLastButtons]=\"true\"\n [class.hide-range]=\"config.ui?.showRange === false\"\n (page)=\"onPageChange($event)\"\n >\n </mat-paginator>\n }\n }\n }\n </ng-template>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block}.praxis-list-root{container-type:inline-size;--p-list-radius: var(--md-sys-shape-corner-medium, 16px);--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-blur: 10px;--p-list-surface: var(--md-sys-color-surface-container);--p-list-surface-low: var(--md-sys-color-surface);--p-list-surface-high: var( --md-sys-color-surface-container-high, var(--md-sys-color-surface-container) );--p-list-foreground: var(--md-sys-color-on-surface);--p-list-foreground-muted: var(--md-sys-color-on-surface-variant);--p-list-accent: var(--md-sys-color-primary);--p-list-accent-weak: var(--md-sys-color-primary-container);--p-list-item-surface: var( --md-sys-color-surface-container-low, var(--md-sys-color-surface) );--p-list-item-border: 1px solid var(--md-sys-color-outline-variant);--p-list-item-hover-surface: var(--md-sys-color-surface-container-low);--p-list-item-active-surface: var(--md-sys-color-surface-container);--p-list-item-selected-surface: var(--md-sys-color-surface-container);--p-list-grad-from: var(--md-sys-color-primary-container);--p-list-grad-to: var(--md-sys-color-tertiary-container);--p-list-grad-angle: 135deg;--p-list-grad-foreground: var( --md-sys-color-on-primary-container, var(--md-sys-color-on-surface) );--p-list-grad-foreground-muted: color-mix( in srgb, var(--p-list-grad-foreground) 76%, transparent );--p-list-leading-width: 36px;--p-list-trailing-min-width: 140px;--p-list-trailing-max-width: 320px;--p-list-item-gap: 10px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 10px;--p-list-item-stack-gap: 0px;--p-list-meta-size: .875rem;--p-list-meta-weight: 500;--p-list-chip-height: 22px;--p-list-chip-font-size: 12px;--p-list-trailing-padding-right: 8px;--p-list-action-button-height: 32px;--p-list-tile-minW: 240px;--p-list-tile-gap: 12px;--p-list-tile-padding: 12px;--p-list-tile-radius: 12px;--p-list-tile-media-radius: 12px;--p-list-tile-media-ratio: 1 / 1;--p-list-tile-hover-overlay: .04;--p-list-tile-press-overlay: .08;--p-list-tile-press-scale: .99}.list-assistant{display:flex;justify-content:flex-end;gap:8px;padding:4px 4px 8px}.action-loading{opacity:.65}.action-spinner{width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center}.action-loading .mat-mdc-button-touch-target,.action-loading .mdc-button__label{opacity:.7}.skin-elevated,.skin-outline,.skin-flat,.skin-neumorphism{--p-list-item-surface: var( --mdc-elevated-card-container-color, var(--p-list-surface) );--p-list-item-border: var(--p-list-border)}.skin-elevated .item-card,.skin-outline .item-card,.skin-flat .item-card,.skin-neumorphism .item-card{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:var(--p-list-radius);box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .item-tile,.skin-outline .item-tile,.skin-flat .item-tile,.skin-neumorphism .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));box-shadow:var(--p-list-shadow);border:var(--p-list-border)}.skin-elevated .mat-mdc-list-item .list-item-content,.skin-outline .mat-mdc-list-item .list-item-content,.skin-flat .mat-mdc-list-item .list-item-content,.skin-neumorphism .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * .75);box-shadow:var(--p-list-shadow);border:var(--p-list-item-border);color:var(--p-list-foreground)}.skin-outline{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline)}.skin-flat{--p-list-shadow: none;--p-list-border: 1px solid var(--md-sys-color-outline-variant)}.skin-neumorphism{--p-list-shadow: var(--md-sys-elevation-level2);--p-list-border: 1px solid var(--md-sys-color-outline-variant);--p-list-radius: 1.25rem}.skin-pill-soft .item-card,.skin-pill-soft .item-tile{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border)}.skin-pill-soft .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border-radius:calc(var(--p-list-radius) * 1.3);box-shadow:var(--md-sys-elevation-level1);border:var(--p-list-border);color:var(--p-list-foreground)}.skin-gradient-tile{--p-list-foreground: var(--p-list-grad-foreground);--p-list-foreground-muted: var(--p-list-grad-foreground-muted);--p-list-item-hover-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-active-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) );--p-list-item-selected-surface: linear-gradient( var(--p-list-grad-angle), var(--p-list-grad-from), var(--p-list-grad-to) )}.skin-gradient-tile .item-card,.skin-gradient-tile .item-tile{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-gradient-tile .tile-media{background:color-mix(in srgb,var(--md-sys-color-surface) 74%,transparent);border-color:color-mix(in srgb,var(--p-list-foreground) 22%,transparent)}.skin-gradient-tile .tile-media mat-icon,.skin-gradient-tile .tile-meta,.skin-gradient-tile .tile-trailing,.skin-gradient-tile .feature,.skin-gradient-tile .secondary,.skin-gradient-tile .meta{color:var(--p-list-foreground-muted)}.skin-gradient-tile .tile-status,.skin-gradient-tile [data-rich-node-type=badge] .prx-rich-badge{color:var(--md-sys-color-on-secondary-container, var(--p-list-foreground));background:var(--md-sys-color-secondary-container, rgba(255, 255, 255, .72))}.skin-gradient-tile .mat-mdc-list-item .list-item-content{background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));border-radius:var(--p-list-radius);color:var(--p-list-foreground)}.skin-glass .item-card,.skin-glass .item-tile{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.skin-glass .mat-mdc-list-item .list-item-content{background:color-mix(in srgb,var(--md-sys-color-surface-container-low, rgba(255, 255, 255, .03)) 65%,transparent);border-radius:var(--p-list-radius);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 55%,transparent);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur));color:var(--p-list-foreground)}.density-compact .mat-mdc-list-item,.density-compact .item-card{--p-list-item-padding-y: 6px;--p-list-item-padding-x: 10px;--p-list-item-gap: 8px}.density-comfortable .mat-mdc-list-item,.density-comfortable .item-card{--p-list-item-padding-y: 8px;--p-list-item-padding-x: 12px;--p-list-item-gap: 10px}.praxis-list-root.lines-3 .mat-mdc-list-item{min-height:68px}.density-compact{--p-list-tile-gap: 10px;--p-list-tile-padding: 10px;--p-list-tile-minW: 188px}.density-comfortable{--p-list-tile-gap: 12px;--p-list-tile-padding: 12px}.item-spacing-none{--p-list-item-stack-gap: 0px}.item-spacing-tight{--p-list-item-stack-gap: 4px;--p-list-tile-gap: 10px}.item-spacing-default{--p-list-item-stack-gap: 6px;--p-list-tile-gap: 12px}.item-spacing-relaxed{--p-list-item-stack-gap: 14px;--p-list-tile-gap: 20px}.list-item-content{box-sizing:border-box;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) minmax(var(--p-list-trailing-min-width),min(34vw,var(--p-list-trailing-max-width)));align-items:center;gap:var(--p-list-item-gap);padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x);width:100%;min-width:0;border-radius:calc(var(--p-list-radius) * .75);overflow:visible}.list-item-content--row-layout{--p-list-row-template-columns: var(--p-list-leading-width) minmax(0, 1fr) minmax(var(--p-list-trailing-min-width), max-content);--p-list-row-gap: var(--p-list-item-gap);--p-list-row-align-items: center;grid-template-columns:var(--p-list-row-template-columns);gap:var(--p-list-row-gap);align-items:var(--p-list-row-align-items);position:relative}.list-row-main-action{position:absolute;inset:0;z-index:1;padding:0;border:0;border-radius:inherit;background:transparent;cursor:pointer}.list-row-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-slot{position:relative;z-index:0;min-width:0;height:100%;align-self:stretch;display:flex;align-items:var(--p-list-row-slot-align-items, center);gap:8px}.list-item-content--row-layout :is(.list-row-slot--actions,.list-row-slot--expand,.list-row-slot--trailing){z-index:2}.list-item-content--row-layout .list-row-slot>praxis-rich-content,.list-item-content--row-layout .list-row-slot>praxis-list-metric,.list-item-content--row-layout .list-row-slot>praxis-list-compose,.list-item-content--row-layout .list-row-slot>praxis-list-runtime-component{min-width:0}.list-row-slot--leading{justify-content:center}.list-row-slot--primary,.list-row-slot--secondary,.list-row-slot--identity{min-width:0}.list-row-slot--identity>praxis-list-compose,.list-row-slot--primary>praxis-list-compose,.list-row-slot--secondary>praxis-list-compose{width:100%}.list-row-slot--meta{color:var(--p-list-foreground);font-variant-numeric:tabular-nums}.list-row-slot--trailing{flex-wrap:nowrap;justify-content:flex-end;gap:8px}.list-row-slot .primary,.list-row-slot .secondary,.list-row-slot .meta,.list-row-slot .trailing{min-width:0}.list-item-main-action{grid-column:1/3;display:grid;grid-template-columns:var(--p-list-leading-width) minmax(0,1fr);align-items:center;gap:var(--p-list-item-gap);min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.list-item-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:12px}.list-item-leading{display:flex;align-items:center;justify-content:center;min-width:0;min-height:100%}.list-item-leading>praxis-rich-content,.list-row-slot--leading>praxis-rich-content{min-width:0;max-width:100%}:host ::ng-deep .list-item-leading [data-rich-node-type=icon],:host ::ng-deep .list-row-slot--leading [data-rich-node-type=icon]{width:36px;height:36px;border-radius:10px;display:inline-flex;align-items:center;justify-content:center;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 14%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 28%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary, #06b6d4));box-sizing:border-box;flex-shrink:0}.leading-placeholder{width:24px;height:24px;display:inline-block}.list-item-text{min-width:0;display:grid;align-content:center;gap:2px}.list-item-trailing{box-sizing:border-box;min-width:0;width:100%;max-width:var(--p-list-trailing-max-width);display:flex;flex-wrap:nowrap;align-self:center;align-content:center;align-items:center;justify-content:end;gap:8px;text-align:end;padding-right:var(--p-list-trailing-padding-right)}.list-item-trailing>*{align-self:center}.list-item-content--row-layout .list-item-actions{justify-content:flex-end}.list-item-actions{width:max-content;justify-self:end;align-self:center;display:flex;align-items:center;justify-content:flex-end;gap:4px;flex-wrap:wrap;max-width:100%;min-height:var(--p-list-action-button-height)}.list-item-actions .mat-mdc-button-base{min-height:var(--p-list-action-button-height);height:var(--p-list-action-button-height);display:inline-flex;align-items:center}.expand-toggle{color:var(--p-list-foreground-muted)}.mat-mdc-list-item .list-item-content{background:var(--p-list-item-surface);border:var(--p-list-item-border);transition:background .15s ease,box-shadow .15s ease,transform .15s ease}.mat-mdc-list-item{height:auto;align-items:stretch;overflow:visible}.mat-mdc-list-item.mdc-list-item--with-one-line,.mat-mdc-list-item.mdc-list-item--with-two-lines,.mat-mdc-list-item.mdc-list-item--with-three-lines,.mat-mdc-list-item-single-line,.mat-mdc-list-item-two-line,.mat-mdc-list-item-three-line{height:auto!important}.mdc-list-item{overflow:visible}.density-compact .mat-mdc-list-item{min-height:40px}.density-comfortable .mat-mdc-list-item{min-height:46px}.praxis-list-root:not(.density-compact):not(.density-comfortable) .mat-mdc-list-item{min-height:48px}.mat-mdc-list-item .mdc-list-item__content,.mat-mdc-list-item .mdc-list-item__primary-text{display:block!important;width:100%!important;height:auto!important;padding:0!important;margin:0!important;overflow:visible!important;box-sizing:border-box}.mat-mdc-list-item{padding:0!important;box-sizing:border-box}.praxis-list-root mat-list mat-list-item:not(:last-child),.praxis-list-root .mat-mdc-list-item:not(:last-child){margin-bottom:var(--p-list-item-stack-gap)}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:var(--p-list-radius, 12px);box-shadow:var(--p-list-shadow, 0 1px 3px rgba(0, 0, 0, .2))}.praxis-list-root[data-item-appearance=card] .mat-mdc-list-item:hover .list-item-content,.praxis-list-root.item-appearance-card .mat-mdc-list-item:hover .list-item-content{border-color:var(--md-sys-color-primary, #6750a4);box-shadow:var(--md-sys-elevation-level2, 0 2px 6px rgba(0, 0, 0, .25))}.praxis-list-root[data-item-appearance=capsule] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-capsule .mat-mdc-list-item .list-item-content{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));border-radius:9999px;box-shadow:var(--p-list-shadow, none)}.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-item-content,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-item-content,.praxis-list-root[data-item-appearance=flat] .mat-mdc-list-item .list-row-shell--selectable,.praxis-list-root.item-appearance-flat .mat-mdc-list-item .list-row-shell--selectable{background:transparent;border:none;box-shadow:none;border-radius:0}.mat-mdc-list-item:hover .list-item-content{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-item-content{background:var(--p-list-item-active-surface)}.mat-mdc-list-item:focus-visible .list-item-content{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.list-row-shell{width:100%;min-width:0}.list-row-shell--selectable{display:grid;grid-template-columns:minmax(0,1fr);align-items:stretch;border-radius:calc(var(--p-list-radius) * .75);background:var(--p-list-item-surface);border:var(--p-list-item-border);color:var(--p-list-foreground);overflow:hidden;transition:background .15s ease,box-shadow .15s ease,border-color .15s ease}.list-row-shell--selectable.list-row-shell--with-control{grid-template-columns:minmax(0,1fr) auto}.list-selection-control{position:relative;z-index:2;display:flex;align-items:flex-start;justify-content:center;padding:var(--p-list-item-padding-y) var(--p-list-item-padding-x) var(--p-list-item-padding-y) 0}.list-selection-control mat-radio-button{--mat-radio-selected-icon-color: var(--p-list-foreground);--mat-radio-selected-hover-icon-color: var(--p-list-foreground);--mat-radio-selected-focus-icon-color: var(--p-list-foreground);--mat-radio-selected-pressed-icon-color: var(--p-list-foreground);--mat-radio-checked-ripple-color: var(--p-list-foreground)}.praxis-list-root .mat-mdc-list-item .list-row-shell--selectable .list-item-content{background:transparent;border:0;border-radius:0;box-shadow:none}.mat-mdc-list-item:hover .list-row-shell--selectable{background:var(--p-list-item-hover-surface)}.mat-mdc-list-item:active .list-row-shell--selectable{background:var(--p-list-item-active-surface)}.list-row-shell--selected{background:var(--p-list-item-selected-surface);border-color:var(--md-sys-color-outline-variant)}.skin-elevated .list-row-shell--selectable,.skin-outline .list-row-shell--selectable,.skin-flat .list-row-shell--selectable,.skin-neumorphism .list-row-shell--selectable{background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-item-border);box-shadow:var(--p-list-shadow)}.skin-pill-soft .list-row-shell--selectable{border-radius:calc(var(--p-list-radius) * 1.3);background:var(--mdc-elevated-card-container-color, var(--p-list-surface));border:var(--p-list-border);box-shadow:var(--md-sys-elevation-level1)}.skin-gradient-tile .list-row-shell--selectable{border-radius:var(--p-list-radius);background:linear-gradient(var(--p-list-grad-angle),var(--p-list-grad-from),var(--p-list-grad-to));color:var(--p-list-foreground)}.skin-glass .list-row-shell--selectable{border-radius:var(--p-list-radius);background:var(--md-sys-color-surface-container-low);border:1px solid var(--md-sys-color-outline-variant);backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.executive-inline-skin{--p-list-leading-width: 56px;--p-list-trailing-min-width: 232px;--p-list-item-padding-x: 14px;--p-list-item-padding-y: 8px;--p-list-item-gap: 10px;--p-list-surface: #f8fafb;--p-list-surface-low: #ffffff;--p-list-item-surface: #ffffff;--p-list-item-hover-surface: #f7fafc;--p-list-item-active-surface: #eef4f8;--p-list-item-selected-surface: #eef4f8;--p-list-foreground: #17324d;--p-list-foreground-muted: #5b6f84;--p-list-chip-background: #eef4f8;--p-list-chip-color: #17324d;--p-list-chip-border-color: #d5e2ec;--md-sys-color-on-surface: #17324d;--md-sys-color-on-surface-variant: #5b6f84;--md-sys-color-surface: #ffffff;--md-sys-color-surface-container-low: #f1f5f9;--md-sys-color-surface-container: #e2e8f0;--md-sys-color-surface-container-high: #e2e8f0;--md-sys-color-surface-container-highest: #cbd5e1;--md-sys-color-outline: #94a3b8;--md-sys-color-outline-variant: #d5e2ec;--praxis-icon-btn-fg: #6d7f93;color:var(--p-list-foreground)}.executive-inline-skin .list-item-content--row-layout.exec-row-layout{min-height:72px;padding:12px 16px;background:linear-gradient(180deg,#fff,#fbfcfd)!important;border:1px solid #dce5ec!important;border-radius:18px;box-shadow:0 1px 2px #0f223a08,0 4px 14px #0f223a08!important;color:#17324d!important}.executive-inline-skin .mat-mdc-list-item:hover .list-item-content--row-layout.exec-row-layout{background:linear-gradient(180deg,#fff,#f7fafc)!important}.executive-inline-skin .list-item-content--row-layout.exec-row-layout+.item-expansion{margin-left:10px;margin-right:10px}.executive-inline-skin .list-item-content--row-layout.exec-row-layout .list-row-slot{min-height:34px}.executive-inline-skin .list-row-slot--leading{justify-content:center}.executive-inline-skin .list-row-slot--identity{align-items:center;padding-right:4px}.executive-inline-skin .list-row-slot--balance,.executive-inline-skin .list-row-slot--limit,.executive-inline-skin .list-row-slot--risk,.executive-inline-skin .list-row-slot--alerts{justify-content:center;padding-inline:2px}.executive-inline-skin .list-row-slot--owner{justify-content:flex-start;padding-left:0}.executive-inline-skin .list-row-slot--actions{justify-content:flex-end;padding-left:0}.executive-inline-skin .list-row-slot--expand{justify-content:center}:host ::ng-deep .executive-inline-skin .docs-expansion-leading{width:44px;height:44px;display:inline-flex;align-items:center;justify-content:center;border-radius:15px;background:linear-gradient(180deg,#edf4f9,#e6eef5);color:#1b5f86;font-size:1rem;font-weight:800;letter-spacing:.02em;box-shadow:0 1px 3px #1b5f861f;border:1px solid #dbe7f0}:host ::ng-deep .executive-inline-skin .exec-balance-metric,:host ::ng-deep .executive-inline-skin .exec-limit-metric,:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:0;gap:5px}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__label,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__label{font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-balance-metric .p-list-metric__value,:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__value{font-size:.96rem;font-weight:800;letter-spacing:-.02em;color:#0d1f34;line-height:1.05}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__caption{font-size:.66rem;font-weight:700;color:#8090a1}:host ::ng-deep .executive-inline-skin .exec-limit-metric .p-list-metric__progress{width:68px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric{min-width:84px;justify-items:center}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__main{gap:5px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__value{font-size:1.02rem;font-weight:800;letter-spacing:-.024em;line-height:1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__progress{width:56px;justify-self:center;height:3px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption{font-size:.7rem;font-weight:700;line-height:1.1}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__below-progress,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__caption--below-progress{justify-self:center;margin-top:-1px}:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon mat-icon,:host ::ng-deep .executive-inline-skin .exec-risk-metric .p-list-metric__icon .prx-rich-icon{width:15px;height:15px;font-size:15px}.executive-inline-skin .list-item-actions{gap:6px;flex-wrap:nowrap}.executive-inline-skin .list-row-slot--actions .list-item-actions{justify-content:flex-end}.executive-inline-skin .list-item-actions button,.executive-inline-skin .expand-toggle{--praxis-icon-btn-fg: #6d7f93;width:30px;height:30px;min-width:30px;border-radius:12px;color:#6d7f93!important}.executive-inline-skin .list-item-actions button mat-icon,.executive-inline-skin .expand-toggle mat-icon{width:18px;height:18px;font-size:18px}.executive-inline-skin .item-expansion{position:relative;margin-top:-10px;padding:22px 26px;background:linear-gradient(180deg,#fcfdfe,#f5f8fb);border-color:#e4eaf0;border-radius:0 0 22px 22px;box-shadow:inset 0 1px #ffffffdb;color:var(--p-list-foreground)}.lead-image{position:relative;width:96px;height:72px;border-radius:12px;overflow:hidden}.lead-image img{width:100%;height:100%;object-fit:cover;display:block}.lead-image .lead-badge{position:absolute;left:8px;bottom:8px}.inline-image{position:relative;width:20px;height:20px;border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.inline-image img{width:100%;height:100%;object-fit:cover;display:block}.inline-image .inline-badge{position:absolute;left:2px;bottom:2px}.model-media .lead-image{width:136px;height:96px;border-radius:16px}.model-media .list-item-content{gap:16px}.model-media .item-card{--p-list-leading-width: 136px}.model-hotel .lead-image{width:160px;height:110px;border-radius:18px}.model-hotel .item-card{--p-list-leading-width: 160px}.primary,.secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis}.primary{-webkit-line-clamp:1;font-weight:600;color:var(--p-list-foreground)}.secondary{-webkit-line-clamp:1;color:var(--p-list-foreground-muted)}.lines-3 .tertiary{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-tile .primary{-webkit-line-clamp:2;font-size:.95rem;line-height:1.25rem}.item-tile .secondary{-webkit-line-clamp:2;font-size:.8rem;line-height:1.1rem}.tertiary{color:var(--p-list-foreground-muted)}.features{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:inherit}.feature{display:inline-flex;align-items:center;gap:6px}.feature-line{display:block}.feature-progress{display:block;width:88px;height:4px;margin-top:6px;border-radius:999px;background:#dbe5eb;overflow:hidden}.feature-progress__value{display:block;height:100%;border-radius:inherit;background:#2f9b69}.meta{color:var(--p-list-foreground);font-size:var(--p-list-meta-size);font-weight:var(--p-list-meta-weight);font-variant-numeric:tabular-nums;max-width:100%;min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta>span,.meta praxis-rich-content{min-width:0;display:inline-flex;align-items:center;justify-content:flex-end;gap:4px;line-height:1.15;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta .mat-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;line-height:1;vertical-align:middle}.trailing{color:var(--p-list-foreground-muted);margin-left:0;max-width:100%;min-width:0;display:inline-flex;justify-content:flex-end;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.trailing praxis-rich-content{min-width:0}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge],:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge]{background:transparent;color:inherit}:host ::ng-deep .meta praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .trailing praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge,:host ::ng-deep .list-row-slot praxis-rich-content .prx-rich-node[data-rich-node-type=badge] .prx-rich-badge{min-height:22px;padding:2px 10px;border-radius:999px;font-size:.72rem;font-weight:600;letter-spacing:.02em;border:1px solid var(--p-list-chip-border-color, transparent);background:var(--p-list-chip-background, var(--md-sys-color-primary-container, #e8def8));color:var(--p-list-chip-color, var(--md-sys-color-on-primary-container, #21005d));line-height:18px}.section-header{display:block;font-size:.85rem;color:var(--p-list-foreground-muted);padding:8px 12px}.section-header praxis-rich-content{display:block;width:100%}.section-header--setup{margin:8px 12px 12px;padding:14px 16px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:color-mix(in srgb,var(--p-list-surface) 92%,var(--md-sys-color-primary) 8%);color:var(--p-list-foreground);font-weight:500}praxis-empty-state-card.section-header,praxis-empty-state-card.section-header--setup{margin:0;padding:0;border:0;border-radius:0;background:transparent;font-size:inherit;font-weight:inherit}.praxis-list-root mat-list{display:block;padding-bottom:12px}.praxis-list-root .mat-divider{margin-left:var(--p-list-item-padding-x);margin-right:var(--p-list-item-padding-x)}.item-expansion{margin:0 var(--p-list-item-padding-x) var(--p-list-item-stack-gap);padding:var(--p-list-expansion-padding, 14px 16px);background:var(--md-sys-color-surface-container-low, var(--p-list-surface));border:1px solid var(--md-sys-color-outline-variant);border-radius:calc(var(--p-list-radius) * .75);color:var(--p-list-foreground);white-space:normal;min-width:0}.praxis-list-root[data-item-appearance=card] .list-row-shell--expanded .list-item-content,.praxis-list-root.item-appearance-card .list-row-shell--expanded .list-item-content{border-bottom-left-radius:0;border-bottom-right-radius:0}.praxis-list-root[data-item-appearance=card] .item-expansion--attached,.praxis-list-root.item-appearance-card .item-expansion--attached{margin:0;border-top:0;border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:var(--p-list-radius, 12px);border-bottom-right-radius:var(--p-list-radius, 12px);background:color-mix(in srgb,var(--md-sys-color-surface-container-low, var(--p-list-surface)) 82%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 65%,transparent)}.skin-glass .item-expansion--attached{backdrop-filter:blur(var(--p-list-blur));-webkit-backdrop-filter:blur(var(--p-list-blur))}.item-expansion--detached,.item-expansion--modal{margin-top:var(--p-list-item-stack-gap);background:var(--md-sys-color-surface-container, var(--p-list-surface));box-shadow:var(--md-sys-elevation-level1)}.item-expansion--modal{border-color:var(--md-sys-color-outline);box-shadow:var(--md-sys-elevation-level3)}.item-expansion-grid{display:grid;grid-template-columns:var(--p-list-expansion-columns, repeat(auto-fit, minmax(220px, 1fr)));gap:var(--p-list-expansion-gap, 16px)}.expansion-section{min-width:0;display:grid;gap:10px;align-content:start}.expansion-section-title{font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-info-list,.expansion-timeline,.expansion-key-value{display:grid;gap:10px}.expansion-info-item,.expansion-timeline-item{display:grid;gap:4px;min-width:0;padding:10px 12px;border-radius:14px;background:var(--p-list-item-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent 28%)}.expansion-info-title,.expansion-timeline-title{font-size:.92rem;font-weight:600;color:var(--p-list-foreground);white-space:normal;overflow-wrap:break-word}.expansion-info-value,.expansion-timeline-meta,.expansion-timeline-description,.expansion-empty{font-size:.82rem;line-height:1.45;color:var(--p-list-foreground-muted);white-space:normal;overflow-wrap:break-word}.expansion-chip-list{display:flex;flex-wrap:wrap;gap:8px}.expansion-chip{background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant)}.expansion-key-value{margin:0;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px 12px}.expansion-key-value-row{display:grid;align-content:start;gap:3px;min-width:0;overflow:hidden;padding:8px 10px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-surface-container-highest, rgba(255, 255, 255, .04)) 45%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12)) 45%,transparent)}.expansion-key-value-row dt,.expansion-key-value-row dd{margin:0;min-width:0;white-space:normal;overflow-wrap:break-word}.expansion-key-value-row dt{font-size:.68rem;font-weight:700;line-height:1.25;letter-spacing:.05em;text-transform:uppercase;color:var(--p-list-foreground-muted)}.expansion-key-value-row dd{font-size:.85rem;font-weight:600;line-height:1.35;color:var(--p-list-foreground)}.cards-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, max(300px, var(--p-list-tile-minW)))), 1fr)));gap:max(var(--p-list-tile-gap),16px)}.tiles-grid{display:grid;grid-template-columns:var(--p-list-card-grid-columns, repeat(auto-fit, minmax(min(100%, var(--p-list-card-minW, var(--p-list-tile-minW))), 1fr)));gap:var(--p-list-tile-gap)}.item-tile{position:relative;display:flex;flex-direction:column;gap:10px;padding:var(--p-list-tile-padding);border-radius:var(--p-list-tile-radius);background:var(--p-list-surface);border:var(--p-list-border);color:var(--p-list-foreground);cursor:pointer;min-height:160px;transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out}.item-tile:hover{box-shadow:var(--md-sys-elevation-level2);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-tile:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.tile-main-action{display:flex;flex:1;min-width:0;flex-direction:column;gap:10px;color:inherit;cursor:pointer}.tile-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.tile-media{width:100%;aspect-ratio:var(--p-list-tile-media-ratio);border-radius:var(--p-list-tile-media-radius);background:var(--p-list-item-surface);border:1px solid var(--md-sys-color-outline-variant);display:grid;place-items:center;overflow:hidden}.tile-media img{width:100%;height:100%;object-fit:cover;display:block}.tile-media mat-icon{font-size:28px;height:28px;width:28px;color:var(--p-list-foreground-muted)}.tile-body{display:grid;gap:6px;min-width:0}.tile-meta{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tile-trailing{font-size:.75rem;color:var(--p-list-foreground-muted);white-space:nowrap}.tiles-features{display:flex;flex-wrap:wrap;gap:8px;color:inherit}.tile-status{position:absolute;top:10px;right:10px}.tile-actions{position:absolute;top:8px;left:8px;display:flex;gap:4px;opacity:0;pointer-events:none;transform:translateY(-2px);transition:opacity .16s ease-out,transform .16s ease-out}.item-tile:hover .tile-actions,.item-tile:focus-within .tile-actions{opacity:1;pointer-events:auto;transform:translateY(0)}@media(hover:none){.tile-actions{opacity:1;pointer-events:auto;transform:none}}@media(max-width:600px){.tiles-grid,.cards-grid{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}}@media(prefers-reduced-motion:reduce){.item-tile,.tile-actions{transition:none}.item-tile:active{transform:none}.item-card{transition:none}.item-card:active{transform:none}}.item-card{padding:max(var(--p-list-tile-padding),16px);display:flex;flex-direction:column;gap:var(--p-list-item-gap);min-height:var(--p-list-card-minH, 220px);position:relative;cursor:pointer;background:var(--p-list-surface);border:var(--p-list-border);border-radius:var(--p-list-tile-radius);box-shadow:var(--p-list-shadow);transition:box-shadow .16s ease-out,border-color .16s ease-out,transform .12s ease-out,background .16s ease-out;--p-list-leading-width: 96px;--p-list-trailing-min-width: 0px}.density-compact .item-card{min-height:var(--p-list-card-minH, 148px)}.pdx-list-item--primary{--p-list-item-rule-tone: var(--md-sys-color-primary, #06b6d4);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 52%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--success{--p-list-item-rule-tone: var(--p-color-success, #10b981);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 48%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 9%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--warning{--p-list-item-rule-tone: var( --p-color-warning, var(--md-sys-color-tertiary, #f59e0b) );border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 54%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 10%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--danger{--p-list-item-rule-tone: var(--md-sys-color-error, #ef4444);border-color:color-mix(in srgb,var(--p-list-item-rule-tone) 56%,var(--md-sys-color-outline-variant))!important;background:color-mix(in srgb,var(--p-list-item-rule-tone) 11%,var(--p-list-item-surface, var(--p-list-surface)))!important;box-shadow:inset 3px 0 0 var(--p-list-item-rule-tone)!important}.pdx-list-item--muted{opacity:.78;border-style:dashed!important;background:color-mix(in srgb,var(--md-sys-color-surface-variant) 34%,var(--p-list-surface))!important}.pdx-list-item--neutral{border-color:var(--md-sys-color-outline-variant)!important;background:var(--p-list-surface)!important}.card-main-action{display:block;width:100%;min-width:0;padding:0;border:0;background:transparent;color:inherit;text-align:start;font:inherit;cursor:pointer}.card-main-action:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:calc(var(--p-list-tile-radius) - 4px)}.item-card .list-item-content{display:block;padding:0;min-width:0;overflow:hidden}.item-card .list-item-leading{position:absolute;top:18px;left:18px;min-height:0;z-index:1}.item-card .leading-placeholder{width:36px;height:36px}.item-card .leading-icon.mat-icon,.item-card .list-item-leading>mat-icon{width:36px;height:36px;line-height:36px;font-size:20px;display:inline-flex;align-items:center;justify-content:center;border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent));color:var(--md-sys-color-primary)}.item-card .list-item-text{display:grid;gap:9px;padding-left:50px;width:100%;min-width:0;box-sizing:border-box}.item-card .primary{padding-right:min(50%,160px);font-size:1rem;font-weight:800;letter-spacing:-.01em;line-height:1.18;min-width:0;overflow-wrap:anywhere}.item-card .secondary{color:var(--p-list-foreground-muted);font-weight:600;line-height:1.35;min-width:0;overflow-wrap:anywhere}.item-card .features{display:flex;flex-direction:column;gap:8px;margin-top:2px}.item-card .feature{display:inline-flex;align-items:start;gap:8px;min-width:0;max-width:100%;overflow-wrap:anywhere}.item-card .feature mat-icon{margin-top:1px;color:var(--p-list-foreground-muted);opacity:.86}.item-card .list-item-trailing{min-width:var(--p-list-trailing-min-width);grid-column:1/-1;align-items:stretch;padding-right:0}.card-detail-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:10px;margin-top:16px}.card-detail{min-width:0;padding:11px 12px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 82%,transparent);border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 22%,transparent),color-mix(in srgb,var(--p-list-surface) 92%,transparent));box-shadow:inset 0 1px #ffffff14}.card-detail__label{display:block;margin-bottom:3px;color:var(--p-list-foreground-muted);font-size:.68rem;font-weight:700;letter-spacing:.08em;line-height:1.1;text-transform:uppercase}.card-detail__value{display:block;min-width:0;color:var(--p-list-foreground);font-size:.94rem;font-weight:800;line-height:1.2;overflow-wrap:normal;word-break:normal}.card-detail__value,.card-detail__value *{white-space:nowrap}.card-detail--balance .card-detail__value{color:var(--md-sys-color-primary)}.card-detail--limit .card-detail__value{color:var(--md-sys-color-error)}.card-detail--risk .card-detail__value{color:var(--md-sys-color-tertiary, var(--p-list-foreground))}.item-card:hover{box-shadow:var(--md-sys-elevation-level3);border-color:var(--md-sys-color-outline-variant);background:var(--p-list-item-hover-surface)}.item-card:active{transform:scale(var(--p-list-tile-press-scale));background:var(--p-list-item-active-surface)}.card-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:6px 8px 4px;border-top:1px solid var(--md-sys-color-outline-variant);margin-top:auto}.status-overlay{position:absolute;top:14px;right:14px;max-width:min(42%,148px);overflow:hidden;pointer-events:none}.status-overlay .mat-mdc-chip{pointer-events:auto;width:100%;min-width:0;max-width:100%}.status-overlay .mdc-evolution-chip__text-label,.status-overlay .mat-mdc-chip-action-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.leading-icon.mat-icon,.list-item-leading>mat-icon,.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon],[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon]{width:36px;height:36px;min-width:36px;line-height:36px;font-size:19px;display:inline-flex;align-items:center;justify-content:center;border-radius:10px;box-sizing:border-box;background:var(--p-list-leading-icon-bg, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 15%, transparent));border:1px solid var(--p-list-leading-icon-border, color-mix(in srgb, var(--md-sys-color-primary, #06b6d4) 30%, transparent));color:var(--p-list-leading-icon-color, var(--md-sys-color-primary));box-shadow:inset 0 1px #ffffff0f}.list-item-leading ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon,[data-row-slot=leading] ::ng-deep praxis-rich-content .prx-rich-node[data-rich-node-type=icon] .prx-rich-icon{font-size:19px;width:19px;height:19px;line-height:19px;color:inherit}.mat-mdc-chip{--mdc-chip-container-height: var(--p-list-chip-height);--mdc-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mat-chip-elevated-container-color: var( --p-list-chip-background, var(--md-sys-color-surface-container-high) );--mdc-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mat-chip-label-text-color: var( --p-list-chip-color, var(--md-sys-color-on-surface) );--mdc-chip-outline-color: var(--p-list-chip-border-color, transparent);--mat-chip-outline-color: var(--p-list-chip-border-color, transparent);font-size:var(--p-list-chip-font-size);font-weight:600;letter-spacing:.02em;border-radius:999px!important;background-color:var(--p-list-chip-background, var(--md-sys-color-surface-container-high))!important;color:var(--p-list-chip-color, var(--md-sys-color-on-surface))!important;border:1px solid var(--p-list-chip-border-color, transparent)!important}:host ::ng-deep .mat-mdc-chip .mdc-evolution-chip__text-label,:host ::ng-deep .mat-mdc-chip .mat-mdc-chip-action-label{color:var(--p-list-chip-color, inherit)!important;font-weight:600;font-size:.72rem;letter-spacing:.02em}.meta .mat-icon{font-size:18px;height:18px;width:18px}.features{overflow:hidden}@keyframes shimmer{0%{background-position:-468px 0}to{background-position:468px 0}}.skeleton{animation-duration:1.2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:shimmer;animation-timing-function:linear;background:linear-gradient(to right,var(--md-sys-color-surface-container-low) 8%,var(--md-sys-color-surface-container) 18%,var(--md-sys-color-surface-container-low) 33%);background-size:800px 104px;position:relative}.skeleton-avatar{width:32px;height:32px;border-radius:50%}.skeleton-line{height:10px;margin:6px 0;border-radius:6px}.skeleton-chip{width:48px;height:18px;border-radius:999px}.chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important;color:var(--p-list-chip-color, currentColor)!important}.w-60{width:60%}.w-40{width:40%}.list-collection-toolbar{display:flex;align-items:center;gap:12px;padding:12px;margin-bottom:8px;color:var(--p-list-foreground);background:var(--p-list-surface-low);border:var(--p-list-border);border-radius:calc(var(--p-list-radius) * .75)}.list-toolbar-search{flex:1 1 320px;min-width:220px;max-width:440px}.list-toolbar-commands{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px;margin-inline-start:auto}.list-toolbar-commands button{border-radius:8px}.list-toolbar-commands button .mat-icon{margin-right:6px}.list-toolbar-sort{width:200px}.list-remote-error{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:12px;margin:8px 4px 0;padding:16px;color:var(--md-sys-color-on-error-container);background:var(--md-sys-color-error-container);border-radius:calc(var(--p-list-radius) * .75)}.list-remote-error__copy{display:flex;flex-direction:column;gap:4px;min-width:0}.list-remote-error__copy span{color:color-mix(in srgb,var(--md-sys-color-on-error-container) 82%,transparent);line-height:1.45}.list-remote-error button{color:var(--md-sys-color-on-error-container);--mat-button-outlined-label-text-color: var( --md-sys-color-on-error-container );--mat-button-outlined-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent );--mdc-outlined-button-label-text-color: var( --md-sys-color-on-error-container );--mdc-outlined-button-outline-color: color-mix( in srgb, var(--md-sys-color-on-error-container) 42%, transparent )}.mat-mdc-paginator{margin-top:14px;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--p-list-surface-low);color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-container{min-height:40px;padding:4px 8px;gap:6px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select{margin-left:8px;width:92px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-text-field-wrapper{--mdc-outlined-text-field-container-color: color-mix( in srgb, var(--p-list-surface-low) 92%, var(--md-sys-color-on-surface) 8% );--mdc-outlined-text-field-input-text-color: var(--p-list-foreground);min-height:40px;padding-inline:12px 8px;background:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;background-color:color-mix(in srgb,var(--p-list-surface-low) 92%,var(--md-sys-color-on-surface) 8%)!important;color:var(--p-list-foreground)!important}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-form-field-infix{min-height:40px;padding-block:8px;width:auto}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-page-size-select .mat-mdc-select-trigger{min-height:24px;padding-right:2px;color:var(--p-list-foreground)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-range-label,:host ::ng-deep .mat-mdc-paginator .mat-mdc-select-value-text{font-size:12px;color:var(--p-list-foreground-muted)}.list-paginator-total{margin-top:14px;padding:4px 8px 0;font-size:12px;color:var(--p-list-foreground-muted)}:host ::ng-deep .mat-mdc-paginator.hide-range .mat-mdc-paginator-range-label{display:none}::ng-deep .praxis-list-paginator-select-panel.mat-mdc-select-panel{--mat-select-panel-background-color: var( --md-sys-color-surface-container, var(--mat-sys-surface-container) );background:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;background-color:var(--md-sys-color-surface-container, var(--mat-sys-surface-container))!important;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 70%,transparent);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, #000) 28%,transparent)}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option{--mat-option-label-text-color: var(--md-sys-color-on-surface, #111827);color:var(--md-sys-color-on-surface, #111827)!important}::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled),::ng-deep .praxis-list-paginator-select-panel .mat-mdc-option.mat-mdc-option-active{--mat-option-hover-state-layer-color: color-mix( in srgb, var(--md-sys-color-primary, #2f7cff) 14%, transparent );background:color-mix(in srgb,var(--md-sys-color-primary, #2f7cff) 14%,transparent)!important;color:var(--md-sys-color-on-surface, #111827)!important}.muted{color:var(--p-list-foreground-muted)}@container (max-width: 720px){.executive-inline-skin .list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.executive-inline-skin .list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--primary,.executive-inline-skin .list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.executive-inline-skin .list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.executive-inline-skin .list-item-content--row-layout .list-row-slot--meta,.executive-inline-skin .list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.executive-inline-skin .list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.executive-inline-skin .list-selection-control{padding-left:0}.executive-inline-skin .list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.executive-inline-skin .list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.executive-inline-skin .list-item-trailing .list-item-actions{margin-inline-start:auto}.executive-inline-skin .item-expansion{margin-left:0;margin-right:0}.executive-inline-skin .list-collection-toolbar{flex-direction:column;align-items:stretch}.executive-inline-skin .list-toolbar-search,.executive-inline-skin .list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.executive-inline-skin .list-toolbar-commands{width:100%;margin-inline-start:0}.executive-inline-skin .list-toolbar-sort{flex:1 1 100%}.executive-inline-skin .list-toolbar-commands button{flex:0 0 auto}.executive-inline-skin .list-remote-error{grid-template-columns:auto minmax(0,1fr)}.executive-inline-skin .list-remote-error button{grid-column:1/-1;justify-self:stretch}}@container (max-width: 420px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}@media(max-width:640px){.list-item-content{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr)}.list-item-content--row-layout{grid-template-columns:var(--p-list-leading-width) minmax(0,1fr) max-content;grid-auto-flow:row;align-items:start}.list-item-content--row-layout .list-row-slot--leading{grid-column:1;grid-row:1}.list-item-content--row-layout .list-row-slot--primary,.list-item-content--row-layout .list-row-slot--identity{grid-column:2/-1;grid-row:1}.list-item-content--row-layout .list-row-slot--secondary{grid-column:2/-1;grid-row:2}.list-item-content--row-layout :is(.list-row-slot--primary,.list-row-slot--secondary){white-space:normal;overflow-wrap:anywhere}.list-item-content--row-layout .list-row-slot--meta,.list-item-content--row-layout .list-row-slot--risk{grid-column:2;grid-row:3;justify-content:flex-start}.list-item-content--row-layout .list-row-slot--trailing{grid-column:3;grid-row:3;justify-content:flex-end}.list-selection-control{padding-left:0}.list-item-content--row-layout :is(.list-row-slot--balance,.list-row-slot--limit,.list-row-slot--alerts,.list-row-slot--owner,.list-row-slot--actions,.list-row-slot--expand){grid-column:1/-1}.list-item-trailing{grid-column:1/-1;display:flex;flex-wrap:wrap;justify-content:flex-start;padding-right:0;align-items:center;text-align:start;max-width:none;width:100%;gap:8px}.list-item-trailing .list-item-actions{margin-inline-start:auto}.item-expansion{margin-left:0;margin-right:0}.list-collection-toolbar{flex-direction:column;align-items:stretch}.list-toolbar-search,.list-toolbar-sort{flex:0 0 auto;width:100%;max-width:none;min-width:0}.list-toolbar-commands{width:100%;margin-inline-start:0}.list-toolbar-sort{flex:1 1 100%}.list-toolbar-commands button{flex:0 0 auto}.list-remote-error{grid-template-columns:auto minmax(0,1fr)}.list-remote-error button{grid-column:1/-1;justify-self:stretch}}.list-loading-status{display:flex;align-items:center;gap:8px;padding:12px 0;color:inherit;--mat-progress-spinner-active-indicator-color: currentColor}.list-loading-status:empty{display:none}.praxis-list-virtual-viewport,.praxis-list-bounded-viewport{display:block;width:100%;overflow-y:auto;outline:none;padding-right:4px;box-sizing:border-box;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent) transparent}.praxis-list-virtual-viewport::-webkit-scrollbar,.praxis-list-bounded-viewport::-webkit-scrollbar{width:6px;height:6px}.praxis-list-virtual-viewport::-webkit-scrollbar-track,.praxis-list-bounded-viewport::-webkit-scrollbar-track{background:transparent}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--md-sys-color-outline-variant, #64748b) 55%,transparent);border-radius:999px}.praxis-list-virtual-viewport::-webkit-scrollbar-thumb:hover,.praxis-list-bounded-viewport::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--md-sys-color-on-surface-variant, #94a3b8) 72%,transparent)}.praxis-list-virtual-viewport{height:var(--p-list-viewport-height, 400px);contain:strict}.praxis-list-virtual-viewport .praxis-list-virtual-list{padding-top:0;padding-bottom:0}.list-item-menu-trigger{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--md-sys-shape-corner-full, 9999px);color:var(--p-list-foreground-muted, inherit);transition:background-color .15s ease,color .15s ease}.list-item-menu-trigger:hover{background-color:var(--p-list-item-hover-surface, rgba(0, 0, 0, .04));color:var(--p-list-foreground, inherit)}\n"] }]
|
|
12972
13397
|
}], propDecorators: { config: [{
|
|
12973
13398
|
type: Input
|
|
12974
13399
|
}], listId: [{
|
|
@@ -12997,7 +13422,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
12997
13422
|
type: Output
|
|
12998
13423
|
}], exportAction: [{
|
|
12999
13424
|
type: Output
|
|
13000
|
-
}], configPatchChange: [{ type: i0.Output, args: ["configPatchChange"] }]
|
|
13425
|
+
}], configPatchChange: [{ type: i0.Output, args: ["configPatchChange"] }], searchInputRef: [{
|
|
13426
|
+
type: ViewChild,
|
|
13427
|
+
args: ['searchInput']
|
|
13428
|
+
}] } });
|
|
13001
13429
|
|
|
13002
13430
|
class PraxisListSkinPreviewComponent {
|
|
13003
13431
|
skin;
|
|
@@ -14048,17 +14476,66 @@ class PraxisListConfigEditor {
|
|
|
14048
14476
|
if (!name)
|
|
14049
14477
|
continue;
|
|
14050
14478
|
names.push(name);
|
|
14479
|
+
const type = f.type ? f.type.trim() : undefined;
|
|
14480
|
+
const domainMeta = this.extractFieldDomainMeta(f, type);
|
|
14051
14481
|
nextMeta[name] = {
|
|
14052
14482
|
name,
|
|
14053
14483
|
...(f.label ? { label: f.label.trim() } : {}),
|
|
14054
|
-
...(
|
|
14484
|
+
...(type ? { type } : {}),
|
|
14055
14485
|
...(f.description ? { description: f.description.trim() } : {}),
|
|
14486
|
+
...(domainMeta.enumValues?.length ? { enumValues: domainMeta.enumValues } : {}),
|
|
14487
|
+
...(domainMeta.optionLabels ? { optionLabels: domainMeta.optionLabels } : {}),
|
|
14056
14488
|
};
|
|
14057
14489
|
}
|
|
14058
14490
|
this.fieldMetaByName = nextMeta;
|
|
14059
14491
|
this.fields = names;
|
|
14060
14492
|
}
|
|
14061
14493
|
}
|
|
14494
|
+
extractFieldDomainMeta(rawField, fallbackType) {
|
|
14495
|
+
if (!rawField || typeof rawField !== 'object') {
|
|
14496
|
+
return {};
|
|
14497
|
+
}
|
|
14498
|
+
const f = rawField;
|
|
14499
|
+
const rawOptions = f['enumValues'] ??
|
|
14500
|
+
f['enum'] ??
|
|
14501
|
+
f['options'] ??
|
|
14502
|
+
(f['uiConfig'] && typeof f['uiConfig'] === 'object'
|
|
14503
|
+
? f['uiConfig']['options']
|
|
14504
|
+
: undefined);
|
|
14505
|
+
const enumValues = [];
|
|
14506
|
+
const seen = new Set();
|
|
14507
|
+
const optionLabels = {};
|
|
14508
|
+
if (Array.isArray(rawOptions)) {
|
|
14509
|
+
for (const item of rawOptions) {
|
|
14510
|
+
if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
|
|
14511
|
+
const key = String(item).trim();
|
|
14512
|
+
if (key && !seen.has(key)) {
|
|
14513
|
+
seen.add(key);
|
|
14514
|
+
enumValues.push(key);
|
|
14515
|
+
}
|
|
14516
|
+
}
|
|
14517
|
+
else if (item && typeof item === 'object') {
|
|
14518
|
+
const rec = item;
|
|
14519
|
+
const key = String(rec['value'] ?? rec['key'] ?? rec['id'] ?? rec['code'] ?? '').trim();
|
|
14520
|
+
const label = String(rec['label'] ?? rec['text'] ?? rec['description'] ?? '').trim();
|
|
14521
|
+
if (key && !seen.has(key)) {
|
|
14522
|
+
seen.add(key);
|
|
14523
|
+
enumValues.push(key);
|
|
14524
|
+
}
|
|
14525
|
+
if (key && label && label !== key) {
|
|
14526
|
+
optionLabels[key] = label;
|
|
14527
|
+
}
|
|
14528
|
+
}
|
|
14529
|
+
}
|
|
14530
|
+
}
|
|
14531
|
+
if (enumValues.length === 0 && String(fallbackType || '').trim().toLowerCase() === 'boolean') {
|
|
14532
|
+
enumValues.push('true', 'false');
|
|
14533
|
+
}
|
|
14534
|
+
return {
|
|
14535
|
+
...(enumValues.length > 0 ? { enumValues } : {}),
|
|
14536
|
+
...(Object.keys(optionLabels).length > 0 ? { optionLabels } : {}),
|
|
14537
|
+
};
|
|
14538
|
+
}
|
|
14062
14539
|
getFieldLabel(fieldName) {
|
|
14063
14540
|
const key = String(fieldName ?? '').trim();
|
|
14064
14541
|
if (!key)
|
|
@@ -14392,6 +14869,11 @@ class PraxisListConfigEditor {
|
|
|
14392
14869
|
});
|
|
14393
14870
|
this.document = document;
|
|
14394
14871
|
this.working = document.config;
|
|
14872
|
+
this.lastNonEmptyResourcePath = String(this.working?.dataSource?.resourcePath ?? '')
|
|
14873
|
+
.trim()
|
|
14874
|
+
.replace(/^\/+|\/+$/g, '')
|
|
14875
|
+
.replace(/^api\//i, '')
|
|
14876
|
+
.toLowerCase();
|
|
14395
14877
|
this.resetVisualMappingState();
|
|
14396
14878
|
this.hydrateMappingFromTemplating(this.working.templating);
|
|
14397
14879
|
this.hydrateUiEditorFromConfig();
|
|
@@ -14553,11 +15035,19 @@ class PraxisListConfigEditor {
|
|
|
14553
15035
|
f?.hint ||
|
|
14554
15036
|
cat?.description ||
|
|
14555
15037
|
'').trim();
|
|
15038
|
+
const primaryDomain = this.extractFieldDomainMeta(f, type);
|
|
15039
|
+
const fallbackDomain = !primaryDomain.enumValues?.length && cat
|
|
15040
|
+
? this.extractFieldDomainMeta(cat, type)
|
|
15041
|
+
: undefined;
|
|
15042
|
+
const enumValues = primaryDomain.enumValues ?? fallbackDomain?.enumValues;
|
|
15043
|
+
const optionLabels = primaryDomain.optionLabels ?? fallbackDomain?.optionLabels;
|
|
14556
15044
|
nextMeta[name] = {
|
|
14557
15045
|
name,
|
|
14558
15046
|
...(label ? { label } : {}),
|
|
14559
15047
|
...(type ? { type } : {}),
|
|
14560
15048
|
...(description ? { description } : {}),
|
|
15049
|
+
...(enumValues?.length ? { enumValues } : {}),
|
|
15050
|
+
...(optionLabels ? { optionLabels } : {}),
|
|
14561
15051
|
};
|
|
14562
15052
|
}
|
|
14563
15053
|
this.fieldMetaByName = nextMeta;
|
|
@@ -14598,9 +15088,30 @@ class PraxisListConfigEditor {
|
|
|
14598
15088
|
]
|
|
14599
15089
|
.map((field) => String(field ?? '').trim())
|
|
14600
15090
|
.filter(Boolean);
|
|
14601
|
-
|
|
15091
|
+
if (mappedDataFields.some((field) => !validFields.has(field))) {
|
|
15092
|
+
return true;
|
|
15093
|
+
}
|
|
15094
|
+
const templateRefs = new Set();
|
|
15095
|
+
const collectRefs = (val) => {
|
|
15096
|
+
if (typeof val === 'string') {
|
|
15097
|
+
for (const match of val.matchAll(/\$\{item\.([A-Za-z_][\w]*)(?:\|[^}]*)?\}/g)) {
|
|
15098
|
+
templateRefs.add(match[1]);
|
|
15099
|
+
}
|
|
15100
|
+
return;
|
|
15101
|
+
}
|
|
15102
|
+
if (!val || typeof val !== 'object')
|
|
15103
|
+
return;
|
|
15104
|
+
if (Array.isArray(val)) {
|
|
15105
|
+
val.forEach(collectRefs);
|
|
15106
|
+
return;
|
|
15107
|
+
}
|
|
15108
|
+
Object.values(val).forEach(collectRefs);
|
|
15109
|
+
};
|
|
15110
|
+
collectRefs(this.working?.templating);
|
|
15111
|
+
return Array.from(templateRefs).some((field) => !validFields.has(field));
|
|
14602
15112
|
}
|
|
14603
15113
|
pendingRemoteSlotInference = false;
|
|
15114
|
+
lastNonEmptyResourcePath = '';
|
|
14604
15115
|
syncSchemaFieldsFromWorking(immediate = false) {
|
|
14605
15116
|
const resourcePath = this.getActiveDataSourceMode() === 'remote'
|
|
14606
15117
|
? String(this.working?.dataSource?.resourcePath || '').trim()
|
|
@@ -14626,9 +15137,33 @@ class PraxisListConfigEditor {
|
|
|
14626
15137
|
});
|
|
14627
15138
|
}
|
|
14628
15139
|
onResourcePathChange(value) {
|
|
15140
|
+
const prevNormalized = this.lastNonEmptyResourcePath;
|
|
15141
|
+
const nextNormalized = String(value ?? '')
|
|
15142
|
+
.trim()
|
|
15143
|
+
.replace(/^\/+|\/+$/g, '')
|
|
15144
|
+
.replace(/^api\//i, '')
|
|
15145
|
+
.toLowerCase();
|
|
14629
15146
|
if (this.working?.dataSource) {
|
|
14630
15147
|
this.working.dataSource.resourcePath = value;
|
|
14631
15148
|
}
|
|
15149
|
+
if (nextNormalized.length === 0) {
|
|
15150
|
+
this.fields = [];
|
|
15151
|
+
this.fieldMetaByName = {};
|
|
15152
|
+
}
|
|
15153
|
+
else if (prevNormalized !== nextNormalized) {
|
|
15154
|
+
this.lastNonEmptyResourcePath = nextNormalized;
|
|
15155
|
+
if (prevNormalized.length > 0) {
|
|
15156
|
+
this.fields = [];
|
|
15157
|
+
this.fieldMetaByName = {};
|
|
15158
|
+
if (this.working?.dataSource) {
|
|
15159
|
+
delete this.working.dataSource.query;
|
|
15160
|
+
delete this.working.dataSource.sort;
|
|
15161
|
+
}
|
|
15162
|
+
this.queryJson = '';
|
|
15163
|
+
this.queryError = '';
|
|
15164
|
+
this.sortField = undefined;
|
|
15165
|
+
}
|
|
15166
|
+
}
|
|
14632
15167
|
this.resourcePathChanges.next({
|
|
14633
15168
|
path: String(value ?? '').trim(),
|
|
14634
15169
|
immediate: false,
|
|
@@ -14932,7 +15467,74 @@ class PraxisListConfigEditor {
|
|
|
14932
15467
|
target.locale = locale;
|
|
14933
15468
|
this.onMappingChanged();
|
|
14934
15469
|
}
|
|
15470
|
+
resolveStatusDomainField(explicitField) {
|
|
15471
|
+
if (this.getActiveDataSourceMode() === 'local') {
|
|
15472
|
+
return undefined;
|
|
15473
|
+
}
|
|
15474
|
+
const candidates = [
|
|
15475
|
+
explicitField,
|
|
15476
|
+
this.mappingTrailing?.field,
|
|
15477
|
+
this.mappingMeta?.type === 'chip' || this.mappingMeta?.type === 'icon'
|
|
15478
|
+
? this.mappingMeta?.field
|
|
15479
|
+
: undefined,
|
|
15480
|
+
this.mappingLeading?.type === 'chip' || this.mappingLeading?.type === 'icon'
|
|
15481
|
+
? this.mappingLeading?.field
|
|
15482
|
+
: undefined,
|
|
15483
|
+
]
|
|
15484
|
+
.map((f) => String(f ?? '').trim())
|
|
15485
|
+
.filter(Boolean);
|
|
15486
|
+
for (const candidate of candidates) {
|
|
15487
|
+
if (this.fieldMetaByName[candidate]?.enumValues?.length) {
|
|
15488
|
+
return candidate;
|
|
15489
|
+
}
|
|
15490
|
+
}
|
|
15491
|
+
const statusPattern = /(status|situacao|state|ativo|active|fase|etapa|stage|prioridade|priority|risco|risk|severidade|severity)/i;
|
|
15492
|
+
return this.fields.find((f) => statusPattern.test(f) && !!this.fieldMetaByName[f]?.enumValues?.length);
|
|
15493
|
+
}
|
|
15494
|
+
inferSemanticStatusColor(value, index) {
|
|
15495
|
+
const normalized = String(value ?? '')
|
|
15496
|
+
.normalize('NFD')
|
|
15497
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
15498
|
+
.trim()
|
|
15499
|
+
.toLowerCase();
|
|
15500
|
+
if (/^(falhou|failed|erro|error|critico|critical|inativo|inactive|cancelad[oa]|cancelled|canceled|rejeitad[oa]|rejected|bloquead[oa]|blocked|atrasad[oa]|overdue|vencid[oa]|expired|suspens[oa]|suspended|indisponivel|unavailable|alto|high|danger|false|nao|no)$/.test(normalized)) {
|
|
15501
|
+
return 'warn';
|
|
15502
|
+
}
|
|
15503
|
+
if (/^(em_andamento|in_progress|pendente|pending|pausad[oa]|paused|atencao|warning|aguardando|waiting|em_analise|review|processando|processing|rascunho|draft|medio|medium|parcial|partial|ultimas\s*vagas|last\s*spots)$/.test(normalized)) {
|
|
15504
|
+
return 'accent';
|
|
15505
|
+
}
|
|
15506
|
+
if (/^(ativo|active|concluid[oa]|completed|done|aprovad[oa]|approved|planejad[oa]|planned|disponivel|available|aberto|open|ok|normal|baixo|low|sucesso|success|true|sim|yes)$/.test(normalized)) {
|
|
15507
|
+
return 'primary';
|
|
15508
|
+
}
|
|
15509
|
+
const cycle = ['primary', 'accent', 'warn'];
|
|
15510
|
+
return cycle[index % cycle.length];
|
|
15511
|
+
}
|
|
15512
|
+
resolveDomainColorMapEntries(explicitField) {
|
|
15513
|
+
const field = this.resolveStatusDomainField(explicitField);
|
|
15514
|
+
const values = field ? this.fieldMetaByName[field]?.enumValues : undefined;
|
|
15515
|
+
if (!values?.length) {
|
|
15516
|
+
return [];
|
|
15517
|
+
}
|
|
15518
|
+
return values.map((key, index) => ({
|
|
15519
|
+
key,
|
|
15520
|
+
color: this.inferSemanticStatusColor(key, index),
|
|
15521
|
+
}));
|
|
15522
|
+
}
|
|
15523
|
+
resolveDomainLabelMapEntries(explicitField) {
|
|
15524
|
+
const field = this.resolveStatusDomainField(explicitField);
|
|
15525
|
+
const labels = field ? this.fieldMetaByName[field]?.optionLabels : undefined;
|
|
15526
|
+
if (!labels) {
|
|
15527
|
+
return [];
|
|
15528
|
+
}
|
|
15529
|
+
return Object.entries(labels)
|
|
15530
|
+
.filter(([key, label]) => !!key.trim() && !!label.trim())
|
|
15531
|
+
.map(([key, label]) => ({ key: key.trim(), label: label.trim() }));
|
|
15532
|
+
}
|
|
14935
15533
|
defaultStatusColorMapEntries() {
|
|
15534
|
+
const domainEntries = this.resolveDomainColorMapEntries();
|
|
15535
|
+
if (domainEntries.length > 0) {
|
|
15536
|
+
return domainEntries;
|
|
15537
|
+
}
|
|
14936
15538
|
const locale = this.defaultPresetLocale().toLowerCase();
|
|
14937
15539
|
if (locale.startsWith('pt')) {
|
|
14938
15540
|
return [
|
|
@@ -16238,6 +16840,19 @@ class PraxisListConfigEditor {
|
|
|
16238
16840
|
this.onMappingChanged();
|
|
16239
16841
|
}
|
|
16240
16842
|
applyStandardStatusColorMap() {
|
|
16843
|
+
const domainColors = this.resolveDomainColorMapEntries();
|
|
16844
|
+
if (domainColors.length > 0) {
|
|
16845
|
+
this.chipColorMapEntries = domainColors;
|
|
16846
|
+
this.onChipColorMapChanged();
|
|
16847
|
+
if (!this.chipLabelMapEntries || this.chipLabelMapEntries.length === 0) {
|
|
16848
|
+
const domainLabels = this.resolveDomainLabelMapEntries();
|
|
16849
|
+
if (domainLabels.length > 0) {
|
|
16850
|
+
this.chipLabelMapEntries = domainLabels;
|
|
16851
|
+
this.onChipLabelMapChanged();
|
|
16852
|
+
}
|
|
16853
|
+
}
|
|
16854
|
+
return;
|
|
16855
|
+
}
|
|
16241
16856
|
const locale = this.defaultPresetLocale().toLowerCase();
|
|
16242
16857
|
this.chipColorMapEntries = locale.startsWith('pt')
|
|
16243
16858
|
? [
|
|
@@ -17653,13 +18268,76 @@ class PraxisListConfigEditor {
|
|
|
17653
18268
|
}
|
|
17654
18269
|
// UI editor hydration already called in ctor
|
|
17655
18270
|
// Ensure UI.sortOptions are kept when saving via Settings Panel
|
|
18271
|
+
isGenericInferredChipColorMap(map) {
|
|
18272
|
+
if (!map)
|
|
18273
|
+
return true;
|
|
18274
|
+
const entries = Object.entries(map);
|
|
18275
|
+
if (entries.length === 0)
|
|
18276
|
+
return true;
|
|
18277
|
+
const genericDefaults = {
|
|
18278
|
+
ativo: 'primary',
|
|
18279
|
+
active: 'primary',
|
|
18280
|
+
true: 'primary',
|
|
18281
|
+
inativo: 'warn',
|
|
18282
|
+
inactive: 'warn',
|
|
18283
|
+
false: 'warn',
|
|
18284
|
+
};
|
|
18285
|
+
return (entries.length === Object.keys(genericDefaults).length &&
|
|
18286
|
+
entries.every(([k, v]) => genericDefaults[k] === v));
|
|
18287
|
+
}
|
|
18288
|
+
isGenericInferredChipLabelMap(map) {
|
|
18289
|
+
if (!map)
|
|
18290
|
+
return true;
|
|
18291
|
+
const entries = Object.entries(map);
|
|
18292
|
+
if (entries.length === 0)
|
|
18293
|
+
return true;
|
|
18294
|
+
const genericDefaults = {
|
|
18295
|
+
true: 'Ativo',
|
|
18296
|
+
false: 'Inativo',
|
|
18297
|
+
ativo: 'Ativo',
|
|
18298
|
+
inativo: 'Inativo',
|
|
18299
|
+
active: 'Ativo',
|
|
18300
|
+
inactive: 'Inativo',
|
|
18301
|
+
};
|
|
18302
|
+
return (entries.length === Object.keys(genericDefaults).length &&
|
|
18303
|
+
entries.every(([k, v]) => genericDefaults[k] === v));
|
|
18304
|
+
}
|
|
17656
18305
|
inferFromFields() {
|
|
17657
18306
|
if (!this.fields?.length)
|
|
17658
18307
|
return;
|
|
18308
|
+
const preTemplating = this.working?.templating;
|
|
18309
|
+
const validFields = new Set(this.fields);
|
|
18310
|
+
const prevTrailingField = String(this.mappingTrailing?.field ?? '').trim();
|
|
18311
|
+
const isPrevTrailingGrounded = !prevTrailingField || validFields.has(prevTrailingField);
|
|
18312
|
+
const hadCustomChipColorMap = isPrevTrailingGrounded &&
|
|
18313
|
+
!this.isGenericInferredChipColorMap(preTemplating?.chipColorMap);
|
|
18314
|
+
const hadCustomChipLabelMap = isPrevTrailingGrounded &&
|
|
18315
|
+
!this.isGenericInferredChipLabelMap(preTemplating?.chipLabelMap);
|
|
17659
18316
|
const inferred = inferListAuthoringDocument(this.buildCurrentDocument(), {
|
|
17660
18317
|
schemaFieldNames: this.fields,
|
|
17661
18318
|
});
|
|
17662
18319
|
this.applyIncomingDocument(inferred);
|
|
18320
|
+
const trailingField = this.mappingTrailing?.field;
|
|
18321
|
+
const isTrailingBoolean = !!trailingField &&
|
|
18322
|
+
this.fieldMetaByName[trailingField]?.type?.toLowerCase() === 'boolean';
|
|
18323
|
+
if (this.mappingTrailing?.type === 'chip' &&
|
|
18324
|
+
trailingField &&
|
|
18325
|
+
!isTrailingBoolean &&
|
|
18326
|
+
!hadCustomChipColorMap) {
|
|
18327
|
+
const domainColors = this.resolveDomainColorMapEntries(trailingField);
|
|
18328
|
+
if (domainColors.length > 0) {
|
|
18329
|
+
this.chipColorMapEntries = domainColors;
|
|
18330
|
+
if (!hadCustomChipLabelMap) {
|
|
18331
|
+
const domainLabels = this.resolveDomainLabelMapEntries(trailingField);
|
|
18332
|
+
if (domainLabels.length > 0) {
|
|
18333
|
+
this.chipLabelMapEntries = domainLabels;
|
|
18334
|
+
}
|
|
18335
|
+
}
|
|
18336
|
+
this.working = this.composeWorkingFromVisualState();
|
|
18337
|
+
this.mappingDirty = false;
|
|
18338
|
+
this.appliedMappingSnapshot = this.getMappingSnapshot();
|
|
18339
|
+
}
|
|
18340
|
+
}
|
|
17663
18341
|
this.markDirty();
|
|
17664
18342
|
this.verify();
|
|
17665
18343
|
}
|