@praxisui/list 10.0.0-rc.37 → 10.0.0-rc.39
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 +74 -38
- package/fesm2022/praxisui-list.mjs +912 -48
- package/package.json +6 -6
- package/src/lib/praxis-list.json-api.md +4 -0
- package/types/praxisui-list.d.ts +53 -2
|
@@ -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 { normalizeResourceQuickViewBinding, resolveValuePresentation, LoggerService, GenericCrudService, deepMerge, validateGlobalActionRefs, providePraxisI18n, PraxisIconDirective, PraxisQuickViewTriggerDirective, ResourceQuickViewService, 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';
|
|
@@ -289,7 +289,19 @@ function evaluateTemplate(def, item, options) {
|
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
|
-
const
|
|
292
|
+
const quickView = normalizeResourceQuickViewBinding(def.quickView);
|
|
293
|
+
const out = {
|
|
294
|
+
type: def.type,
|
|
295
|
+
value,
|
|
296
|
+
rawValue,
|
|
297
|
+
class: def.class,
|
|
298
|
+
style: def.style,
|
|
299
|
+
color: def.color,
|
|
300
|
+
variant: def.variant,
|
|
301
|
+
props: def.props,
|
|
302
|
+
imageAlt: def.imageAlt,
|
|
303
|
+
...(quickView ? { quickView, sourceRecord: item } : {}),
|
|
304
|
+
};
|
|
293
305
|
if (def.badge?.expr) {
|
|
294
306
|
const { baseExpr: b2, pipe: p2 } = splitFirstTopLevelPipe(def.badge.expr);
|
|
295
307
|
let badgeVal = evalExpr(b2, { item }, options);
|
|
@@ -1960,6 +1972,12 @@ function templateCaps(slot, label) {
|
|
|
1960
1972
|
allowedValues: ENUMS.templateVariant,
|
|
1961
1973
|
description: `Badge variant for ${label}.`,
|
|
1962
1974
|
},
|
|
1975
|
+
{
|
|
1976
|
+
path: `${base}.quickView`,
|
|
1977
|
+
category: 'templating',
|
|
1978
|
+
valueKind: 'object',
|
|
1979
|
+
description: `Declarative ResourceQuickViewBinding for contextual read-only preview on ${label}.`,
|
|
1980
|
+
},
|
|
1963
1981
|
{
|
|
1964
1982
|
path: `${base}.props`,
|
|
1965
1983
|
category: 'templating',
|
|
@@ -2719,6 +2737,12 @@ const LIST_AI_CAPABILITIES = {
|
|
|
2719
2737
|
allowedValues: ENUMS.actionPlacement,
|
|
2720
2738
|
description: 'Action placement in row layout actions or trailing slot.',
|
|
2721
2739
|
},
|
|
2740
|
+
{
|
|
2741
|
+
path: 'actions[].quickView',
|
|
2742
|
+
category: 'actions',
|
|
2743
|
+
valueKind: 'object',
|
|
2744
|
+
description: 'Declarative ResourceQuickViewBinding for contextual read-only preview triggered by the list item action.',
|
|
2745
|
+
},
|
|
2722
2746
|
{
|
|
2723
2747
|
path: 'actions[].confirmation',
|
|
2724
2748
|
category: 'actions',
|
|
@@ -3390,6 +3414,7 @@ const templateSchema = {
|
|
|
3390
3414
|
variant: { enum: ['filled', 'outlined'] },
|
|
3391
3415
|
},
|
|
3392
3416
|
},
|
|
3417
|
+
quickView: { type: 'object' },
|
|
3393
3418
|
},
|
|
3394
3419
|
};
|
|
3395
3420
|
const templateSlotEnum = [
|
|
@@ -3432,6 +3457,7 @@ const actionSchema = {
|
|
|
3432
3457
|
emitLocal: { type: 'boolean' },
|
|
3433
3458
|
showLoading: { type: 'boolean' },
|
|
3434
3459
|
placement: { enum: ['actions', 'trailing', 'menu'] },
|
|
3460
|
+
quickView: { type: 'object' },
|
|
3435
3461
|
confirmation: {
|
|
3436
3462
|
type: 'object',
|
|
3437
3463
|
properties: {
|
|
@@ -5740,7 +5766,20 @@ function inferTemplatingFromSchema(cfg, fieldNames) {
|
|
|
5740
5766
|
if (!needsPrimary)
|
|
5741
5767
|
return cfg; // respect user config
|
|
5742
5768
|
const pickBy = (preds, accept = () => true) => names.find((n) => preds.some((p) => p.test(String(n))) && accept(n)) || undefined;
|
|
5743
|
-
const primaryName = pickBy([
|
|
5769
|
+
const primaryName = pickBy([
|
|
5770
|
+
/nomeCompleto/i,
|
|
5771
|
+
/fullName/i,
|
|
5772
|
+
/^nome$/i,
|
|
5773
|
+
/^name$/i,
|
|
5774
|
+
/^nome[A-Z]/,
|
|
5775
|
+
/^title$/i,
|
|
5776
|
+
/^titulo$/i,
|
|
5777
|
+
/title/i,
|
|
5778
|
+
/titulo/i,
|
|
5779
|
+
/label/i,
|
|
5780
|
+
]) ||
|
|
5781
|
+
names.find(isReadableBusinessField) ||
|
|
5782
|
+
names[0];
|
|
5744
5783
|
const avatarName = pickBy([
|
|
5745
5784
|
/avatar/i,
|
|
5746
5785
|
/foto/i,
|
|
@@ -5753,10 +5792,10 @@ function inferTemplatingFromSchema(cfg, fieldNames) {
|
|
|
5753
5792
|
const emailName = pickBy([/email/i, /e-mail/i]);
|
|
5754
5793
|
const phoneName = pickBy([/telefone/i, /phone/i, /celular/i, /mobile/i, /whats/i]);
|
|
5755
5794
|
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);
|
|
5795
|
+
const roleName = pickBy([/cargoNome/i, /roleName/i, /funcaoNome/i, /funçãoNome/i, /positionName/i], (n) => n !== primaryName) ||
|
|
5796
|
+
pickBy([/cargo/i, /role/i, /funcao/i, /função/i, /position/i], (n) => n !== primaryName && isReadableBusinessField(n));
|
|
5797
|
+
const departmentName = pickBy([/departamentoNome/i, /departmentName/i, /areaNome/i, /setorNome/i, /teamName/i], (n) => n !== primaryName) ||
|
|
5798
|
+
pickBy([/departamento/i, /department/i, /area/i, /setor/i, /team/i], (n) => n !== primaryName && isReadableBusinessField(n));
|
|
5760
5799
|
const descriptionName = names.find((n) => n !== primaryName && /(desc|descricao|descrição|resumo|summary)/i.test(n));
|
|
5761
5800
|
const secondaryFields = [phoneName, emailName].filter(Boolean);
|
|
5762
5801
|
const fallbackSecondaryFields = [cpfName, emailName].filter(Boolean);
|
|
@@ -5824,6 +5863,22 @@ function inferTemplatingFromSchema(cfg, fieldNames) {
|
|
|
5824
5863
|
false: 'warn',
|
|
5825
5864
|
};
|
|
5826
5865
|
}
|
|
5866
|
+
const usesIdentityRowSlot = Array.isArray(draft.layout?.rowLayout?.columns) &&
|
|
5867
|
+
draft.layout.rowLayout.columns.some((col) => col?.slot === 'identity');
|
|
5868
|
+
if (usesIdentityRowSlot && !t.identity && t.primary) {
|
|
5869
|
+
t.identity = t.secondary
|
|
5870
|
+
? {
|
|
5871
|
+
type: 'compose',
|
|
5872
|
+
props: {
|
|
5873
|
+
compose: {
|
|
5874
|
+
direction: 'column',
|
|
5875
|
+
gap: '2px',
|
|
5876
|
+
items: [t.primary, t.secondary],
|
|
5877
|
+
},
|
|
5878
|
+
},
|
|
5879
|
+
}
|
|
5880
|
+
: t.primary;
|
|
5881
|
+
}
|
|
5827
5882
|
draft.templating = t;
|
|
5828
5883
|
});
|
|
5829
5884
|
return newCfg;
|
|
@@ -6004,16 +6059,116 @@ function shouldInferTemplatingFromSchema(config, schemaFieldNames) {
|
|
|
6004
6059
|
}
|
|
6005
6060
|
function hasUngroundedTemplatingSlot(config, schemaFieldNames) {
|
|
6006
6061
|
const slots = config.templating || {};
|
|
6007
|
-
return
|
|
6062
|
+
return ROW_LAYOUT_TEMPLATE_SLOTS.some((slot) => shouldDropTemplatingSlot(slots[slot], schemaFieldNames, slot));
|
|
6008
6063
|
}
|
|
6009
6064
|
function removeUngroundedTemplatingSlots(config, schemaFieldNames) {
|
|
6010
6065
|
const templating = { ...(config.templating || {}) };
|
|
6011
|
-
|
|
6066
|
+
const droppedSlots = new Set();
|
|
6067
|
+
for (const slot of ROW_LAYOUT_TEMPLATE_SLOTS) {
|
|
6012
6068
|
if (shouldDropTemplatingSlot(templating[slot], schemaFieldNames, slot)) {
|
|
6013
6069
|
delete templating[slot];
|
|
6070
|
+
droppedSlots.add(slot);
|
|
6014
6071
|
}
|
|
6015
6072
|
}
|
|
6016
|
-
|
|
6073
|
+
if (droppedSlots.has('trailing') || droppedSlots.has('meta') || droppedSlots.has('leading')) {
|
|
6074
|
+
const hasRemainingChipSlot = ROW_LAYOUT_TEMPLATE_SLOTS.some((slot) => templating[slot]?.type === 'chip');
|
|
6075
|
+
if (!hasRemainingChipSlot) {
|
|
6076
|
+
delete templating['chipColorMap'];
|
|
6077
|
+
delete templating['chipLabelMap'];
|
|
6078
|
+
}
|
|
6079
|
+
const hasRemainingIconFieldSlot = ROW_LAYOUT_TEMPLATE_SLOTS.some((slot) => templating[slot]?.type === 'icon' &&
|
|
6080
|
+
templateFieldReferences(templating[slot]).length > 0);
|
|
6081
|
+
if (!hasRemainingIconFieldSlot) {
|
|
6082
|
+
delete templating['iconColorMap'];
|
|
6083
|
+
}
|
|
6084
|
+
}
|
|
6085
|
+
const schemaFields = new Set(schemaFieldNames);
|
|
6086
|
+
let nextUi = config.ui;
|
|
6087
|
+
if (nextUi) {
|
|
6088
|
+
let uiMutated = false;
|
|
6089
|
+
const clonedUi = { ...nextUi };
|
|
6090
|
+
if (typeof clonedUi.searchField === 'string' &&
|
|
6091
|
+
clonedUi.searchField.trim().length > 0 &&
|
|
6092
|
+
!schemaFields.has(clonedUi.searchField.trim())) {
|
|
6093
|
+
delete clonedUi.searchField;
|
|
6094
|
+
uiMutated = true;
|
|
6095
|
+
}
|
|
6096
|
+
if (Array.isArray(clonedUi.sortOptions)) {
|
|
6097
|
+
const filteredSortOptions = clonedUi.sortOptions.filter((opt) => {
|
|
6098
|
+
const rawField = String(typeof opt === 'string' ? opt : (opt?.field ?? opt?.value ?? ''))
|
|
6099
|
+
.split(/[,:]/)[0]
|
|
6100
|
+
.trim();
|
|
6101
|
+
return !rawField || schemaFields.has(rawField);
|
|
6102
|
+
});
|
|
6103
|
+
if (filteredSortOptions.length !== clonedUi.sortOptions.length) {
|
|
6104
|
+
clonedUi.sortOptions = filteredSortOptions;
|
|
6105
|
+
uiMutated = true;
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
6108
|
+
if (uiMutated) {
|
|
6109
|
+
nextUi = clonedUi;
|
|
6110
|
+
}
|
|
6111
|
+
}
|
|
6112
|
+
let nextDataSource = config.dataSource;
|
|
6113
|
+
if (Array.isArray(nextDataSource?.sort)) {
|
|
6114
|
+
const filteredSort = nextDataSource.sort.filter((entry) => {
|
|
6115
|
+
const rawField = typeof entry === 'string'
|
|
6116
|
+
? entry.split(/[,:]/)[0].trim()
|
|
6117
|
+
: String(entry?.field ?? '').trim();
|
|
6118
|
+
return !rawField || schemaFields.has(rawField);
|
|
6119
|
+
});
|
|
6120
|
+
if (filteredSort.length !== nextDataSource.sort.length) {
|
|
6121
|
+
const clonedDataSource = { ...nextDataSource };
|
|
6122
|
+
if (filteredSort.length > 0) {
|
|
6123
|
+
clonedDataSource.sort = filteredSort;
|
|
6124
|
+
}
|
|
6125
|
+
else {
|
|
6126
|
+
delete clonedDataSource.sort;
|
|
6127
|
+
}
|
|
6128
|
+
nextDataSource = clonedDataSource;
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
if (Array.isArray(nextDataSource?.query?.sort)) {
|
|
6132
|
+
const currentQuerySort = nextDataSource.query.sort;
|
|
6133
|
+
const filteredQuerySort = currentQuerySort.filter((entry) => {
|
|
6134
|
+
const rawField = typeof entry === 'string'
|
|
6135
|
+
? entry.split(/[,:]/)[0].trim()
|
|
6136
|
+
: String(entry?.field ?? '').trim();
|
|
6137
|
+
return !rawField || schemaFields.has(rawField);
|
|
6138
|
+
});
|
|
6139
|
+
if (filteredQuerySort.length !== currentQuerySort.length) {
|
|
6140
|
+
const clonedQuery = { ...nextDataSource.query };
|
|
6141
|
+
if (filteredQuerySort.length > 0) {
|
|
6142
|
+
clonedQuery['sort'] = filteredQuerySort;
|
|
6143
|
+
}
|
|
6144
|
+
else {
|
|
6145
|
+
delete clonedQuery['sort'];
|
|
6146
|
+
}
|
|
6147
|
+
const clonedDataSource = { ...nextDataSource };
|
|
6148
|
+
if (Object.keys(clonedQuery).length > 0) {
|
|
6149
|
+
clonedDataSource.query = clonedQuery;
|
|
6150
|
+
}
|
|
6151
|
+
else {
|
|
6152
|
+
delete clonedDataSource.query;
|
|
6153
|
+
}
|
|
6154
|
+
nextDataSource = clonedDataSource;
|
|
6155
|
+
}
|
|
6156
|
+
}
|
|
6157
|
+
let nextSelection = config.selection;
|
|
6158
|
+
if (typeof nextSelection?.compareBy === 'string' &&
|
|
6159
|
+
nextSelection.compareBy.trim().length > 0 &&
|
|
6160
|
+
!schemaFields.has(nextSelection.compareBy.trim())) {
|
|
6161
|
+
const clonedSelection = { ...nextSelection };
|
|
6162
|
+
delete clonedSelection.compareBy;
|
|
6163
|
+
nextSelection = clonedSelection;
|
|
6164
|
+
}
|
|
6165
|
+
return {
|
|
6166
|
+
...config,
|
|
6167
|
+
templating,
|
|
6168
|
+
...(nextUi !== config.ui ? { ui: nextUi } : {}),
|
|
6169
|
+
...(nextDataSource !== config.dataSource ? { dataSource: nextDataSource } : {}),
|
|
6170
|
+
...(nextSelection !== config.selection ? { selection: nextSelection } : {}),
|
|
6171
|
+
};
|
|
6017
6172
|
}
|
|
6018
6173
|
function shouldDropTemplatingSlot(template, schemaFieldNames, slot) {
|
|
6019
6174
|
if (!template)
|
|
@@ -6175,6 +6330,10 @@ function normalizeListActionPayloads(actions) {
|
|
|
6175
6330
|
}
|
|
6176
6331
|
next.placement = oneOf(next.placement, ACTION_PLACEMENTS, undefined);
|
|
6177
6332
|
next.showIf = normalizeJsonLogicExpression(next.showIf);
|
|
6333
|
+
if (next.quickView) {
|
|
6334
|
+
next.quickView =
|
|
6335
|
+
normalizeResourceQuickViewBinding(next.quickView) || undefined;
|
|
6336
|
+
}
|
|
6178
6337
|
return stripUndefinedDeep(next);
|
|
6179
6338
|
});
|
|
6180
6339
|
}
|
|
@@ -6894,6 +7053,7 @@ function normalizeTemplateDef(template) {
|
|
|
6894
7053
|
return undefined;
|
|
6895
7054
|
return stripUndefinedDeep({
|
|
6896
7055
|
...template,
|
|
7056
|
+
quickView: normalizeResourceQuickViewBinding(template.quickView) || undefined,
|
|
6897
7057
|
expr: trimToUndefined(template.expr),
|
|
6898
7058
|
class: trimToUndefined(template.class),
|
|
6899
7059
|
style: trimToUndefined(template.style),
|
|
@@ -7346,7 +7506,14 @@ const PRAXIS_LIST_EN_US = {
|
|
|
7346
7506
|
collapseDetails: 'Collapse details',
|
|
7347
7507
|
itemDetails: 'Item details',
|
|
7348
7508
|
emptyState: 'No items available',
|
|
7509
|
+
emptyStateDescription: 'There are no items to display right now.',
|
|
7510
|
+
emptyStateFilteredTitle: 'No results found',
|
|
7511
|
+
emptyStateFilteredDescription: 'Review the active filters or adjust the search term.',
|
|
7512
|
+
emptyStateClearSearchAction: 'Clear search',
|
|
7513
|
+
emptyStateConnectResourceTitle: 'Choose the list resource',
|
|
7349
7514
|
emptyStateConnectResource: 'Connect this list to a resource to load items.',
|
|
7515
|
+
emptyStateConnectResourceAction: 'Select resource',
|
|
7516
|
+
emptyStateConfigureAction: 'Configure list',
|
|
7350
7517
|
recordOpenUnavailable: 'Unable to open details for this item.',
|
|
7351
7518
|
'selection.ariaLabel': 'Selectable list',
|
|
7352
7519
|
'selection.selectItem': 'Select item',
|
|
@@ -7739,7 +7906,14 @@ const PRAXIS_LIST_PT_BR = {
|
|
|
7739
7906
|
collapseDetails: 'Recolher detalhes',
|
|
7740
7907
|
itemDetails: 'Detalhes do item',
|
|
7741
7908
|
emptyState: 'Nenhum item disponível',
|
|
7909
|
+
emptyStateDescription: 'Não há itens para exibir neste momento.',
|
|
7910
|
+
emptyStateFilteredTitle: 'Nenhum resultado encontrado',
|
|
7911
|
+
emptyStateFilteredDescription: 'Revise os filtros ou ajuste o termo de busca.',
|
|
7912
|
+
emptyStateClearSearchAction: 'Limpar busca',
|
|
7913
|
+
emptyStateConnectResourceTitle: 'Escolha o recurso da lista',
|
|
7742
7914
|
emptyStateConnectResource: 'Conecte a lista a um recurso para carregar os itens.',
|
|
7915
|
+
emptyStateConnectResourceAction: 'Selecionar recurso',
|
|
7916
|
+
emptyStateConfigureAction: 'Configurar lista',
|
|
7743
7917
|
recordOpenUnavailable: 'Não foi possível abrir os detalhes deste item.',
|
|
7744
7918
|
'selection.ariaLabel': 'Lista selecionável',
|
|
7745
7919
|
'selection.selectItem': 'Selecionar item',
|
|
@@ -9032,6 +9206,18 @@ class PraxisListComposeComponent {
|
|
|
9032
9206
|
}
|
|
9033
9207
|
}
|
|
9034
9208
|
mapTextNode(node) {
|
|
9209
|
+
if (node?.quickView) {
|
|
9210
|
+
return {
|
|
9211
|
+
type: 'recordReference',
|
|
9212
|
+
label: String(node?.value ?? ''),
|
|
9213
|
+
quickView: node.quickView,
|
|
9214
|
+
className: node?.class,
|
|
9215
|
+
style: this.parseInlineStyle(node?.style),
|
|
9216
|
+
...(node?.sourceRecord !== undefined
|
|
9217
|
+
? { sourceRecord: node.sourceRecord }
|
|
9218
|
+
: {}),
|
|
9219
|
+
};
|
|
9220
|
+
}
|
|
9035
9221
|
return {
|
|
9036
9222
|
type: 'text',
|
|
9037
9223
|
text: String(node?.value ?? ''),
|
|
@@ -9042,6 +9228,19 @@ class PraxisListComposeComponent {
|
|
|
9042
9228
|
mapIconNode(node) {
|
|
9043
9229
|
const iconColorStyle = this.iconStyle(node?.color);
|
|
9044
9230
|
const mergedStyle = [iconColorStyle, node?.style].filter(Boolean).join(';');
|
|
9231
|
+
if (node?.quickView) {
|
|
9232
|
+
return {
|
|
9233
|
+
type: 'recordReference',
|
|
9234
|
+
label: String(node?.value ?? ''),
|
|
9235
|
+
icon: String(node?.value ?? ''),
|
|
9236
|
+
quickView: node.quickView,
|
|
9237
|
+
className: node?.class,
|
|
9238
|
+
style: this.parseInlineStyle(mergedStyle),
|
|
9239
|
+
...(node?.sourceRecord !== undefined
|
|
9240
|
+
? { sourceRecord: node.sourceRecord }
|
|
9241
|
+
: {}),
|
|
9242
|
+
};
|
|
9243
|
+
}
|
|
9045
9244
|
return {
|
|
9046
9245
|
type: 'icon',
|
|
9047
9246
|
icon: String(node?.value ?? ''),
|
|
@@ -9074,6 +9273,10 @@ class PraxisListComposeComponent {
|
|
|
9074
9273
|
...(resolvedTone ? { tone: resolvedTone } : {}),
|
|
9075
9274
|
...(classes ? { className: classes } : {}),
|
|
9076
9275
|
style: this.parseInlineStyle(mergedStyle),
|
|
9276
|
+
...(node?.quickView ? { quickView: node.quickView } : {}),
|
|
9277
|
+
...(node?.sourceRecord !== undefined
|
|
9278
|
+
? { sourceRecord: node.sourceRecord }
|
|
9279
|
+
: {}),
|
|
9077
9280
|
};
|
|
9078
9281
|
}
|
|
9079
9282
|
normalizeGap(gap) {
|
|
@@ -9180,6 +9383,8 @@ class PraxisListComposeComponent {
|
|
|
9180
9383
|
((node?.style || '') ? node.style + ';' : '') +
|
|
9181
9384
|
iconStyle(node?.color)
|
|
9182
9385
|
"
|
|
9386
|
+
[praxisQuickView]="node?.quickView"
|
|
9387
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9183
9388
|
></mat-icon>
|
|
9184
9389
|
}
|
|
9185
9390
|
@case ("image") {
|
|
@@ -9187,6 +9392,8 @@ class PraxisListComposeComponent {
|
|
|
9187
9392
|
class="inline-image"
|
|
9188
9393
|
[ngClass]="node?.class"
|
|
9189
9394
|
[style.cssText]="node?.style"
|
|
9395
|
+
[praxisQuickView]="node?.quickView"
|
|
9396
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9190
9397
|
>
|
|
9191
9398
|
<img [src]="node?.value" [alt]="node?.imageAlt || ''" />
|
|
9192
9399
|
@if (node?.badge?.value) {
|
|
@@ -9222,6 +9429,8 @@ class PraxisListComposeComponent {
|
|
|
9222
9429
|
chipStyle(node?.color, node?.variant) +
|
|
9223
9430
|
(node?.style ? ';' + node.style : '')
|
|
9224
9431
|
"
|
|
9432
|
+
[praxisQuickView]="node?.quickView"
|
|
9433
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9225
9434
|
>
|
|
9226
9435
|
{{ node?.value }}
|
|
9227
9436
|
</mat-chip>
|
|
@@ -9269,13 +9478,18 @@ class PraxisListComposeComponent {
|
|
|
9269
9478
|
</span>
|
|
9270
9479
|
}
|
|
9271
9480
|
@default {
|
|
9272
|
-
<span
|
|
9481
|
+
<span
|
|
9482
|
+
[ngClass]="node?.class"
|
|
9483
|
+
[style.cssText]="node?.style"
|
|
9484
|
+
[praxisQuickView]="node?.quickView"
|
|
9485
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9486
|
+
>{{
|
|
9273
9487
|
node?.value
|
|
9274
9488
|
}}</span>
|
|
9275
9489
|
}
|
|
9276
9490
|
}
|
|
9277
9491
|
</ng-template>
|
|
9278
|
-
`, isInline: true, styles: [":host{display:block;min-width:0;max-width:100%}.p-list-compose{display:flex;min-width:0;max-width:100%;width:100%}.p-list-compose>praxis-rich-content{min-width:0;max-width:100%;width:100%}:host ::ng-deep .primary,:host ::ng-deep .secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}:host ::ng-deep .primary .prx-rich-text,:host ::ng-deep .secondary .prx-rich-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}:host ::ng-deep .primary{-webkit-line-clamp:1;font-weight:600;font-size:var(--p-list-primary-size, .92rem);line-height:1.3;color:var(--p-list-foreground)}:host ::ng-deep .secondary{-webkit-line-clamp:1;font-size:var(--p-list-secondary-size, .78rem);line-height:1.3;color:var(--p-list-foreground-muted)}.p-list-compose--direction-row{flex-direction:row}.p-list-compose--direction-column{flex-direction:column}.p-list-compose--align-start{align-items:flex-start}.p-list-compose--align-center{align-items:center}.p-list-compose--align-end{align-items:flex-end}.p-list-compose--wrap{flex-wrap:wrap}.p-list-compose--nowrap{flex-wrap:nowrap}.p-list-compose__separator{color:var(--p-list-foreground-muted);white-space:pre-wrap}.p-list-compose__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}:host ::ng-deep .mat-mdc-standard-chip:not(.mdc-evolution-chip--disabled){background-color:var( --p-list-chip-background, color-mix(in srgb, var(--p-list-surface-alt) 85%, transparent) )!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, var(--p-list-border))!important}:host ::ng-deep .chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important}\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: 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: 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: 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: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }] });
|
|
9492
|
+
`, isInline: true, styles: [":host{display:block;min-width:0;max-width:100%}.p-list-compose{display:flex;min-width:0;max-width:100%;width:100%}.p-list-compose>praxis-rich-content{min-width:0;max-width:100%;width:100%}:host ::ng-deep .primary,:host ::ng-deep .secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}:host ::ng-deep .primary .prx-rich-text,:host ::ng-deep .secondary .prx-rich-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}:host ::ng-deep .primary{-webkit-line-clamp:1;font-weight:600;font-size:var(--p-list-primary-size, .92rem);line-height:1.3;color:var(--p-list-foreground)}:host ::ng-deep .secondary{-webkit-line-clamp:1;font-size:var(--p-list-secondary-size, .78rem);line-height:1.3;color:var(--p-list-foreground-muted)}.p-list-compose--direction-row{flex-direction:row}.p-list-compose--direction-column{flex-direction:column}.p-list-compose--align-start{align-items:flex-start}.p-list-compose--align-center{align-items:center}.p-list-compose--align-end{align-items:flex-end}.p-list-compose--wrap{flex-wrap:wrap}.p-list-compose--nowrap{flex-wrap:nowrap}.p-list-compose__separator{color:var(--p-list-foreground-muted);white-space:pre-wrap}.praxis-quick-view-trigger{cursor:pointer}.praxis-quick-view-trigger:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:4px}.p-list-compose__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}:host ::ng-deep .mat-mdc-standard-chip:not(.mdc-evolution-chip--disabled){background-color:var( --p-list-chip-background, color-mix(in srgb, var(--p-list-surface-alt) 85%, transparent) )!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, var(--p-list-border))!important}:host ::ng-deep .chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important}\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: 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: 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: "directive", type: PraxisQuickViewTriggerDirective, selector: "[praxisQuickView]", inputs: ["praxisQuickView", "praxisQuickViewRecord", "praxisQuickViewTriggerMode", "praxisQuickViewAnchorId", "praxisQuickViewSourceId", "praxisQuickViewEndpointKey", "praxisQuickViewApiUrlEntry", "praxisQuickViewQueryContext", "praxisQuickViewHoverOpenDelayMs", "praxisQuickViewHoverCloseDelayMs", "praxisQuickViewStopPropagation"], exportAs: ["praxisQuickView"] }, { 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: PraxisListRuntimeComponentComponent, selector: "praxis-list-runtime-component", inputs: ["component"] }] });
|
|
9279
9493
|
}
|
|
9280
9494
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisListComposeComponent, decorators: [{
|
|
9281
9495
|
type: Component,
|
|
@@ -9284,6 +9498,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
9284
9498
|
MatChipsModule,
|
|
9285
9499
|
MatIconModule,
|
|
9286
9500
|
PraxisIconDirective,
|
|
9501
|
+
PraxisQuickViewTriggerDirective,
|
|
9287
9502
|
PraxisRichContent,
|
|
9288
9503
|
PraxisListMetricComponent,
|
|
9289
9504
|
PraxisListRuntimeComponentComponent,
|
|
@@ -9329,6 +9544,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
9329
9544
|
((node?.style || '') ? node.style + ';' : '') +
|
|
9330
9545
|
iconStyle(node?.color)
|
|
9331
9546
|
"
|
|
9547
|
+
[praxisQuickView]="node?.quickView"
|
|
9548
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9332
9549
|
></mat-icon>
|
|
9333
9550
|
}
|
|
9334
9551
|
@case ("image") {
|
|
@@ -9336,6 +9553,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
9336
9553
|
class="inline-image"
|
|
9337
9554
|
[ngClass]="node?.class"
|
|
9338
9555
|
[style.cssText]="node?.style"
|
|
9556
|
+
[praxisQuickView]="node?.quickView"
|
|
9557
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9339
9558
|
>
|
|
9340
9559
|
<img [src]="node?.value" [alt]="node?.imageAlt || ''" />
|
|
9341
9560
|
@if (node?.badge?.value) {
|
|
@@ -9371,6 +9590,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
9371
9590
|
chipStyle(node?.color, node?.variant) +
|
|
9372
9591
|
(node?.style ? ';' + node.style : '')
|
|
9373
9592
|
"
|
|
9593
|
+
[praxisQuickView]="node?.quickView"
|
|
9594
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9374
9595
|
>
|
|
9375
9596
|
{{ node?.value }}
|
|
9376
9597
|
</mat-chip>
|
|
@@ -9418,13 +9639,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
9418
9639
|
</span>
|
|
9419
9640
|
}
|
|
9420
9641
|
@default {
|
|
9421
|
-
<span
|
|
9642
|
+
<span
|
|
9643
|
+
[ngClass]="node?.class"
|
|
9644
|
+
[style.cssText]="node?.style"
|
|
9645
|
+
[praxisQuickView]="node?.quickView"
|
|
9646
|
+
[praxisQuickViewRecord]="node?.sourceRecord"
|
|
9647
|
+
>{{
|
|
9422
9648
|
node?.value
|
|
9423
9649
|
}}</span>
|
|
9424
9650
|
}
|
|
9425
9651
|
}
|
|
9426
9652
|
</ng-template>
|
|
9427
|
-
`, styles: [":host{display:block;min-width:0;max-width:100%}.p-list-compose{display:flex;min-width:0;max-width:100%;width:100%}.p-list-compose>praxis-rich-content{min-width:0;max-width:100%;width:100%}:host ::ng-deep .primary,:host ::ng-deep .secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}:host ::ng-deep .primary .prx-rich-text,:host ::ng-deep .secondary .prx-rich-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}:host ::ng-deep .primary{-webkit-line-clamp:1;font-weight:600;font-size:var(--p-list-primary-size, .92rem);line-height:1.3;color:var(--p-list-foreground)}:host ::ng-deep .secondary{-webkit-line-clamp:1;font-size:var(--p-list-secondary-size, .78rem);line-height:1.3;color:var(--p-list-foreground-muted)}.p-list-compose--direction-row{flex-direction:row}.p-list-compose--direction-column{flex-direction:column}.p-list-compose--align-start{align-items:flex-start}.p-list-compose--align-center{align-items:center}.p-list-compose--align-end{align-items:flex-end}.p-list-compose--wrap{flex-wrap:wrap}.p-list-compose--nowrap{flex-wrap:nowrap}.p-list-compose__separator{color:var(--p-list-foreground-muted);white-space:pre-wrap}.p-list-compose__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}:host ::ng-deep .mat-mdc-standard-chip:not(.mdc-evolution-chip--disabled){background-color:var( --p-list-chip-background, color-mix(in srgb, var(--p-list-surface-alt) 85%, transparent) )!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, var(--p-list-border))!important}:host ::ng-deep .chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important}\n"] }]
|
|
9653
|
+
`, styles: [":host{display:block;min-width:0;max-width:100%}.p-list-compose{display:flex;min-width:0;max-width:100%;width:100%}.p-list-compose>praxis-rich-content{min-width:0;max-width:100%;width:100%}:host ::ng-deep .primary,:host ::ng-deep .secondary{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}:host ::ng-deep .primary .prx-rich-text,:host ::ng-deep .secondary .prx-rich-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}:host ::ng-deep .primary{-webkit-line-clamp:1;font-weight:600;font-size:var(--p-list-primary-size, .92rem);line-height:1.3;color:var(--p-list-foreground)}:host ::ng-deep .secondary{-webkit-line-clamp:1;font-size:var(--p-list-secondary-size, .78rem);line-height:1.3;color:var(--p-list-foreground-muted)}.p-list-compose--direction-row{flex-direction:row}.p-list-compose--direction-column{flex-direction:column}.p-list-compose--align-start{align-items:flex-start}.p-list-compose--align-center{align-items:center}.p-list-compose--align-end{align-items:flex-end}.p-list-compose--wrap{flex-wrap:wrap}.p-list-compose--nowrap{flex-wrap:nowrap}.p-list-compose__separator{color:var(--p-list-foreground-muted);white-space:pre-wrap}.praxis-quick-view-trigger{cursor:pointer}.praxis-quick-view-trigger:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px;border-radius:4px}.p-list-compose__unsupported{display:inline-flex;align-items:center;justify-content:center;width:.75rem;height:.75rem;min-width:.75rem;border:1px dashed var(--md-sys-color-outline-variant);border-radius:999px;overflow:hidden;color:transparent;font-size:0;line-height:0}:host ::ng-deep .mat-mdc-standard-chip:not(.mdc-evolution-chip--disabled){background-color:var( --p-list-chip-background, color-mix(in srgb, var(--p-list-surface-alt) 85%, transparent) )!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, var(--p-list-border))!important}:host ::ng-deep .chip-outlined.mat-mdc-chip{background-color:var(--p-list-chip-background, transparent)!important;color:var(--p-list-chip-color, var(--p-list-foreground))!important;border:1px solid var(--p-list-chip-border-color, currentColor)!important}\n"] }]
|
|
9428
9654
|
}], propDecorators: { compose: [{
|
|
9429
9655
|
type: Input
|
|
9430
9656
|
}] } });
|
|
@@ -9461,6 +9687,9 @@ class PraxisList {
|
|
|
9461
9687
|
static nextSkinScopeId = 0;
|
|
9462
9688
|
customizationEnabled = false;
|
|
9463
9689
|
hostLocale = inject(LOCALE_ID, { optional: true }) ?? 'en-US';
|
|
9690
|
+
quickViewService = inject(ResourceQuickViewService, {
|
|
9691
|
+
optional: true,
|
|
9692
|
+
});
|
|
9464
9693
|
config;
|
|
9465
9694
|
listId;
|
|
9466
9695
|
componentInstanceId;
|
|
@@ -9496,6 +9725,8 @@ class PraxisList {
|
|
|
9496
9725
|
lastQuery = {};
|
|
9497
9726
|
lastRuntimeQueryContextSignature = '';
|
|
9498
9727
|
search$ = new Subject();
|
|
9728
|
+
activeSearchTerm = '';
|
|
9729
|
+
searchInputRef;
|
|
9499
9730
|
get layoutLines() {
|
|
9500
9731
|
return this.config?.layout?.lines ?? 2;
|
|
9501
9732
|
}
|
|
@@ -9652,6 +9883,7 @@ class PraxisList {
|
|
|
9652
9883
|
return typeof this.listId === 'string' && this.listId.trim().length > 0;
|
|
9653
9884
|
}
|
|
9654
9885
|
ngOnDestroy() {
|
|
9886
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
9655
9887
|
if (this.skinStyleElement) {
|
|
9656
9888
|
this.renderer.removeChild(this.hostElement.nativeElement, this.skinStyleElement, false, true);
|
|
9657
9889
|
this.skinStyleElement = undefined;
|
|
@@ -9688,6 +9920,17 @@ class PraxisList {
|
|
|
9688
9920
|
return;
|
|
9689
9921
|
if (this.configPersistenceStrategy === 'input-first')
|
|
9690
9922
|
return;
|
|
9923
|
+
const currentPath = String(this.config?.dataSource?.resourcePath ?? '')
|
|
9924
|
+
.trim()
|
|
9925
|
+
.replace(/^\/+|\/+$/g, '')
|
|
9926
|
+
.toLowerCase();
|
|
9927
|
+
const savedPath = String(saved?.dataSource?.resourcePath ?? '')
|
|
9928
|
+
.trim()
|
|
9929
|
+
.replace(/^\/+|\/+$/g, '')
|
|
9930
|
+
.toLowerCase();
|
|
9931
|
+
if (currentPath.length > 0 && savedPath.length > 0 && currentPath !== savedPath) {
|
|
9932
|
+
return;
|
|
9933
|
+
}
|
|
9691
9934
|
const currentId = this.config?.id;
|
|
9692
9935
|
const persisted = currentId
|
|
9693
9936
|
? { ...saved, id: currentId }
|
|
@@ -9728,9 +9971,17 @@ class PraxisList {
|
|
|
9728
9971
|
const field = this.config?.ui?.searchField;
|
|
9729
9972
|
if (!field)
|
|
9730
9973
|
return;
|
|
9731
|
-
const
|
|
9974
|
+
const normalizedTerm = String(term ?? '').trim();
|
|
9975
|
+
const q = { ...(this.lastQuery || {}) };
|
|
9976
|
+
if (normalizedTerm) {
|
|
9977
|
+
q[field] = term;
|
|
9978
|
+
}
|
|
9979
|
+
else {
|
|
9980
|
+
delete q[field];
|
|
9981
|
+
}
|
|
9732
9982
|
this.lastQuery = q;
|
|
9733
9983
|
this.data.setQuery(q);
|
|
9984
|
+
this.cdr.markForCheck();
|
|
9734
9985
|
});
|
|
9735
9986
|
}
|
|
9736
9987
|
async persistConfig(key, config) {
|
|
@@ -10009,6 +10260,10 @@ class PraxisList {
|
|
|
10009
10260
|
return (Array.isArray(node.items) &&
|
|
10010
10261
|
node.items.some((child) => this.hasDisplayableNodeValue(child)));
|
|
10011
10262
|
}
|
|
10263
|
+
if (node.type === 'component')
|
|
10264
|
+
return true;
|
|
10265
|
+
if (node.type === 'metric')
|
|
10266
|
+
return !this.isEmptyComposeNode(node);
|
|
10012
10267
|
const value = node.value;
|
|
10013
10268
|
if (Array.isArray(value))
|
|
10014
10269
|
return value.length > 0;
|
|
@@ -10033,6 +10288,25 @@ class PraxisList {
|
|
|
10033
10288
|
this.isThemeColor(node.color)) {
|
|
10034
10289
|
return null;
|
|
10035
10290
|
}
|
|
10291
|
+
if (node.quickView) {
|
|
10292
|
+
return [
|
|
10293
|
+
{
|
|
10294
|
+
type: 'recordReference',
|
|
10295
|
+
label: String(node.value),
|
|
10296
|
+
icon: String(node.value),
|
|
10297
|
+
quickView: node.quickView,
|
|
10298
|
+
className: this.joinClasses(options?.slot === 'leading' ? 'leading-icon' : undefined, node.class),
|
|
10299
|
+
style: this.mergeStyleRecords(this.parseInlineStyle(options?.slot === 'leading'
|
|
10300
|
+
? this.leadingIconStyle(node.color, node.style)
|
|
10301
|
+
: node.style), options?.slot === 'leading'
|
|
10302
|
+
? undefined
|
|
10303
|
+
: this.parseInlineStyle(this.iconStyle(node.color))),
|
|
10304
|
+
...(node.sourceRecord !== undefined
|
|
10305
|
+
? { sourceRecord: node.sourceRecord }
|
|
10306
|
+
: {}),
|
|
10307
|
+
},
|
|
10308
|
+
];
|
|
10309
|
+
}
|
|
10036
10310
|
return [
|
|
10037
10311
|
{
|
|
10038
10312
|
type: 'icon',
|
|
@@ -10071,6 +10345,10 @@ class PraxisList {
|
|
|
10071
10345
|
? 'chip-outlined'
|
|
10072
10346
|
: undefined),
|
|
10073
10347
|
style: this.mergeStyleRecords(this.parseInlineStyle(this.joinStyles(this.chipStyle(node.color, node.variant), node.style ? ';' + node.style : undefined))),
|
|
10348
|
+
...(node.quickView ? { quickView: node.quickView } : {}),
|
|
10349
|
+
...(node.sourceRecord !== undefined
|
|
10350
|
+
? { sourceRecord: node.sourceRecord }
|
|
10351
|
+
: {}),
|
|
10074
10352
|
},
|
|
10075
10353
|
];
|
|
10076
10354
|
}
|
|
@@ -10079,6 +10357,20 @@ class PraxisList {
|
|
|
10079
10357
|
this.config?.templating?.metaPrefixIcon) {
|
|
10080
10358
|
return null;
|
|
10081
10359
|
}
|
|
10360
|
+
if (node.quickView) {
|
|
10361
|
+
return [
|
|
10362
|
+
{
|
|
10363
|
+
type: 'recordReference',
|
|
10364
|
+
label: String(node.value ?? ''),
|
|
10365
|
+
quickView: node.quickView,
|
|
10366
|
+
className: node.class,
|
|
10367
|
+
style: this.parseInlineStyle(node.style),
|
|
10368
|
+
...(node.sourceRecord !== undefined
|
|
10369
|
+
? { sourceRecord: node.sourceRecord }
|
|
10370
|
+
: {}),
|
|
10371
|
+
},
|
|
10372
|
+
];
|
|
10373
|
+
}
|
|
10082
10374
|
return [
|
|
10083
10375
|
{
|
|
10084
10376
|
type: 'text',
|
|
@@ -10364,9 +10656,14 @@ class PraxisList {
|
|
|
10364
10656
|
metric.showBar === true;
|
|
10365
10657
|
if (!enabled || !sourceExpr)
|
|
10366
10658
|
return undefined;
|
|
10367
|
-
const
|
|
10659
|
+
const rawText = this.metricText(sourceExpr, item);
|
|
10368
10660
|
const max = Number(progress.max ?? 100);
|
|
10369
10661
|
const mode = progress.mode || metric.barVariant || 'determinate';
|
|
10662
|
+
if (mode !== 'indeterminate' && rawText === undefined)
|
|
10663
|
+
return undefined;
|
|
10664
|
+
const rawValue = Number(rawText);
|
|
10665
|
+
if (mode !== 'indeterminate' && !Number.isFinite(rawValue))
|
|
10666
|
+
return undefined;
|
|
10370
10667
|
const normalizedMax = Number.isFinite(max) && max > 0 ? max : 100;
|
|
10371
10668
|
const percent = Number.isFinite(rawValue)
|
|
10372
10669
|
? Math.max(0, Math.min(100, (rawValue / normalizedMax) * 100))
|
|
@@ -10386,6 +10683,18 @@ class PraxisList {
|
|
|
10386
10683
|
}
|
|
10387
10684
|
if (node.type === 'component')
|
|
10388
10685
|
return false;
|
|
10686
|
+
if (node.type === 'metric') {
|
|
10687
|
+
const hasVal = node.value !== null &&
|
|
10688
|
+
node.value !== undefined &&
|
|
10689
|
+
String(node.value).trim() !== '';
|
|
10690
|
+
const hasCap = node.caption !== null &&
|
|
10691
|
+
node.caption !== undefined &&
|
|
10692
|
+
String(node.caption).trim() !== '';
|
|
10693
|
+
const hasSub = node.subcaption !== null &&
|
|
10694
|
+
node.subcaption !== undefined &&
|
|
10695
|
+
String(node.subcaption).trim() !== '';
|
|
10696
|
+
return !hasVal && !hasCap && !hasSub && !node.progress;
|
|
10697
|
+
}
|
|
10389
10698
|
const value = node.value;
|
|
10390
10699
|
return value === null || value === undefined || String(value).trim() === '';
|
|
10391
10700
|
}
|
|
@@ -10722,6 +11031,81 @@ class PraxisList {
|
|
|
10722
11031
|
const label = this.accessibleItemLabel(item);
|
|
10723
11032
|
return `${label} - ${this.t('itemDetails', 'Detalhes do item').toLowerCase()}`;
|
|
10724
11033
|
}
|
|
11034
|
+
hasCustomEmptyStateTemplate() {
|
|
11035
|
+
return Boolean(this.evalSlot('emptyState', {}));
|
|
11036
|
+
}
|
|
11037
|
+
hasActiveEmptyStateFilters() {
|
|
11038
|
+
if (this.isResourceConnectionMissing())
|
|
11039
|
+
return false;
|
|
11040
|
+
if (this.activeSearchTerm.trim().length > 0)
|
|
11041
|
+
return true;
|
|
11042
|
+
const normalized = normalizePraxisDataQueryContext(this.runtimeQueryContext);
|
|
11043
|
+
const contextFilters = normalized?.filters || {};
|
|
11044
|
+
return Object.values(contextFilters).some((val) => val !== undefined &&
|
|
11045
|
+
val !== null &&
|
|
11046
|
+
String(val).trim().length > 0);
|
|
11047
|
+
}
|
|
11048
|
+
emptyStateIcon() {
|
|
11049
|
+
if (this.isResourceConnectionMissing()) {
|
|
11050
|
+
return 'link';
|
|
11051
|
+
}
|
|
11052
|
+
if (this.hasActiveEmptyStateFilters()) {
|
|
11053
|
+
return 'search_off';
|
|
11054
|
+
}
|
|
11055
|
+
return 'inbox';
|
|
11056
|
+
}
|
|
11057
|
+
emptyStateTitle() {
|
|
11058
|
+
if (this.isResourceConnectionMissing()) {
|
|
11059
|
+
return this.t('emptyStateConnectResourceTitle', 'Escolha o recurso da lista');
|
|
11060
|
+
}
|
|
11061
|
+
if (this.hasActiveEmptyStateFilters()) {
|
|
11062
|
+
return this.t('emptyStateFilteredTitle', 'Nenhum resultado encontrado');
|
|
11063
|
+
}
|
|
11064
|
+
return this.emptyStateLabel();
|
|
11065
|
+
}
|
|
11066
|
+
emptyStateDescription() {
|
|
11067
|
+
if (this.isResourceConnectionMissing()) {
|
|
11068
|
+
return this.emptyStateLabel();
|
|
11069
|
+
}
|
|
11070
|
+
if (this.hasActiveEmptyStateFilters()) {
|
|
11071
|
+
return this.t('emptyStateFilteredDescription', 'Revise os filtros ou ajuste o termo de busca.');
|
|
11072
|
+
}
|
|
11073
|
+
return this.t('emptyStateDescription', 'Não há itens para exibir neste momento.');
|
|
11074
|
+
}
|
|
11075
|
+
emptyStatePrimaryAction() {
|
|
11076
|
+
if (!this.isResourceConnectionMissing() || !this.enableCustomization) {
|
|
11077
|
+
return undefined;
|
|
11078
|
+
}
|
|
11079
|
+
return {
|
|
11080
|
+
label: this.t('emptyStateConnectResourceAction', 'Selecionar recurso'),
|
|
11081
|
+
icon: 'bolt',
|
|
11082
|
+
action: () => this.openQuickConnect(),
|
|
11083
|
+
};
|
|
11084
|
+
}
|
|
11085
|
+
emptyStateSecondaryActions() {
|
|
11086
|
+
if (this.isResourceConnectionMissing()) {
|
|
11087
|
+
if (!this.enableCustomization) {
|
|
11088
|
+
return [];
|
|
11089
|
+
}
|
|
11090
|
+
return [
|
|
11091
|
+
{
|
|
11092
|
+
label: this.t('emptyStateConfigureAction', 'Configurar lista'),
|
|
11093
|
+
icon: 'tune',
|
|
11094
|
+
action: () => this.openConfigEditor(),
|
|
11095
|
+
},
|
|
11096
|
+
];
|
|
11097
|
+
}
|
|
11098
|
+
if (this.activeSearchTerm.trim().length > 0) {
|
|
11099
|
+
return [
|
|
11100
|
+
{
|
|
11101
|
+
label: this.t('emptyStateClearSearchAction', 'Limpar busca'),
|
|
11102
|
+
icon: 'filter_alt_off',
|
|
11103
|
+
action: () => this.clearSearch(),
|
|
11104
|
+
},
|
|
11105
|
+
];
|
|
11106
|
+
}
|
|
11107
|
+
return [];
|
|
11108
|
+
}
|
|
10725
11109
|
emptyStateLabel() {
|
|
10726
11110
|
if (this.isResourceConnectionMissing()) {
|
|
10727
11111
|
return this.t('emptyStateConnectResource', 'Conecte a lista a um recurso para carregar os itens.');
|
|
@@ -10808,10 +11192,35 @@ class PraxisList {
|
|
|
10808
11192
|
const recordOpenReference = recordOpenIntent
|
|
10809
11193
|
? action?.recordOpen
|
|
10810
11194
|
: undefined;
|
|
11195
|
+
const quickViewBinding = normalizeResourceQuickViewBinding(action?.quickView);
|
|
10811
11196
|
const loadingKey = this.buildActionLoadingKey(actionId, item, index);
|
|
10812
11197
|
if (action?.showLoading)
|
|
10813
11198
|
this.actionLoadingState[loadingKey] = true;
|
|
10814
11199
|
try {
|
|
11200
|
+
if (quickViewBinding && this.quickViewService) {
|
|
11201
|
+
const anchorEl = (ev?.currentTarget instanceof HTMLElement
|
|
11202
|
+
? ev.currentTarget
|
|
11203
|
+
: focusOrigin) || this.hostElement.nativeElement;
|
|
11204
|
+
await this.quickViewService.openImmediate({
|
|
11205
|
+
binding: quickViewBinding,
|
|
11206
|
+
sourceRecord: item,
|
|
11207
|
+
anchor: {
|
|
11208
|
+
kind: 'element',
|
|
11209
|
+
element: anchorEl,
|
|
11210
|
+
focusOrigin: anchorEl,
|
|
11211
|
+
},
|
|
11212
|
+
trigger: 'explicit-button',
|
|
11213
|
+
sourceId: this.listId,
|
|
11214
|
+
});
|
|
11215
|
+
if (action?.emitLocal) {
|
|
11216
|
+
this.actionClick.emit({
|
|
11217
|
+
actionId,
|
|
11218
|
+
item,
|
|
11219
|
+
index,
|
|
11220
|
+
});
|
|
11221
|
+
}
|
|
11222
|
+
return;
|
|
11223
|
+
}
|
|
10815
11224
|
if (recordOpenIntent) {
|
|
10816
11225
|
await this.executeRecordOpenAction(actionId, recordOpenReference, item, focusOrigin);
|
|
10817
11226
|
}
|
|
@@ -11306,6 +11715,58 @@ class PraxisList {
|
|
|
11306
11715
|
return value;
|
|
11307
11716
|
}
|
|
11308
11717
|
}
|
|
11718
|
+
openQuickConnect() {
|
|
11719
|
+
if (!this.enableCustomization)
|
|
11720
|
+
return;
|
|
11721
|
+
const key = this.storageKey();
|
|
11722
|
+
const currentResourcePath = String(this.config?.dataSource?.resourcePath || '').trim();
|
|
11723
|
+
const ref = this.settings.open({
|
|
11724
|
+
id: `praxis-list:quick-connect:${key || this.listId || 'default'}`,
|
|
11725
|
+
owner: this.destroyRef,
|
|
11726
|
+
title: this.t('emptyStateConnectResourceTitle', 'Escolha o recurso da lista'),
|
|
11727
|
+
content: {
|
|
11728
|
+
component: ResourceQuickConnectComponent,
|
|
11729
|
+
inputs: {
|
|
11730
|
+
resourcePath: currentResourcePath || undefined,
|
|
11731
|
+
intent: 'collection',
|
|
11732
|
+
},
|
|
11733
|
+
},
|
|
11734
|
+
});
|
|
11735
|
+
const applyResourceSelection = (val, trigger) => {
|
|
11736
|
+
const nextResourcePath = String(val?.resourcePath || '').trim();
|
|
11737
|
+
if (!nextResourcePath)
|
|
11738
|
+
return;
|
|
11739
|
+
const resourceChanged = Boolean(currentResourcePath) &&
|
|
11740
|
+
currentResourcePath !== nextResourcePath;
|
|
11741
|
+
if (resourceChanged) {
|
|
11742
|
+
this.activeSearchTerm = '';
|
|
11743
|
+
if (this.searchInputRef?.nativeElement) {
|
|
11744
|
+
this.searchInputRef.nativeElement.value = '';
|
|
11745
|
+
}
|
|
11746
|
+
}
|
|
11747
|
+
const { data: _ignoredLocalData, query: existingQuery, sort: existingSort, ...restDataSource } = this.config?.dataSource || {};
|
|
11748
|
+
const nextConfig = {
|
|
11749
|
+
...(this.config || {}),
|
|
11750
|
+
dataSource: {
|
|
11751
|
+
...restDataSource,
|
|
11752
|
+
...(resourceChanged
|
|
11753
|
+
? {}
|
|
11754
|
+
: {
|
|
11755
|
+
...(existingQuery ? { query: existingQuery } : {}),
|
|
11756
|
+
...(existingSort ? { sort: existingSort } : {}),
|
|
11757
|
+
}),
|
|
11758
|
+
resourcePath: nextResourcePath,
|
|
11759
|
+
},
|
|
11760
|
+
};
|
|
11761
|
+
this.applyAuthoringPayload(nextConfig, trigger);
|
|
11762
|
+
};
|
|
11763
|
+
ref.applied$?.pipe(takeUntil(this.destroy$)).subscribe((val) => {
|
|
11764
|
+
applyResourceSelection(val, 'settings-applied');
|
|
11765
|
+
});
|
|
11766
|
+
ref.saved$?.pipe(takeUntil(this.destroy$)).subscribe((val) => {
|
|
11767
|
+
applyResourceSelection(val, 'settings-saved');
|
|
11768
|
+
});
|
|
11769
|
+
}
|
|
11309
11770
|
openConfigEditor() {
|
|
11310
11771
|
void this.openConfigEditorPanel().catch((error) => {
|
|
11311
11772
|
this.logger.error('[PraxisList] Error opening list settings.', this.buildLogOptions({ error }));
|
|
@@ -11640,17 +12101,22 @@ class PraxisList {
|
|
|
11640
12101
|
return 'view_list';
|
|
11641
12102
|
}
|
|
11642
12103
|
nextPage() {
|
|
12104
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
11643
12105
|
this.data.nextPage();
|
|
11644
12106
|
}
|
|
11645
12107
|
prevPage() {
|
|
12108
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
11646
12109
|
this.data.prevPage();
|
|
11647
12110
|
}
|
|
11648
12111
|
setPageSize(ps) {
|
|
11649
12112
|
const size = Number(ps);
|
|
11650
|
-
if (isFinite(size) && size > 0)
|
|
12113
|
+
if (isFinite(size) && size > 0) {
|
|
12114
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
11651
12115
|
this.data.setPageSize(size);
|
|
12116
|
+
}
|
|
11652
12117
|
}
|
|
11653
12118
|
onPageChange(event) {
|
|
12119
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
11654
12120
|
this.focusCollectionBeforeReload();
|
|
11655
12121
|
this.data.setPage(event.pageIndex, event.pageSize);
|
|
11656
12122
|
}
|
|
@@ -11666,6 +12132,7 @@ class PraxisList {
|
|
|
11666
12132
|
onSortChange(val) {
|
|
11667
12133
|
if (!val)
|
|
11668
12134
|
return;
|
|
12135
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
11669
12136
|
this.data.setSort([val]);
|
|
11670
12137
|
}
|
|
11671
12138
|
retryRemoteData() {
|
|
@@ -11680,7 +12147,26 @@ class PraxisList {
|
|
|
11680
12147
|
?.focus({ preventScroll: true });
|
|
11681
12148
|
}
|
|
11682
12149
|
onSearchInput(val) {
|
|
11683
|
-
this.
|
|
12150
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
12151
|
+
this.activeSearchTerm = val || '';
|
|
12152
|
+
this.search$.next(this.activeSearchTerm);
|
|
12153
|
+
this.cdr.markForCheck();
|
|
12154
|
+
}
|
|
12155
|
+
clearSearch() {
|
|
12156
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
12157
|
+
this.activeSearchTerm = '';
|
|
12158
|
+
if (this.searchInputRef?.nativeElement) {
|
|
12159
|
+
this.searchInputRef.nativeElement.value = '';
|
|
12160
|
+
}
|
|
12161
|
+
const field = this.config?.ui?.searchField;
|
|
12162
|
+
if (field && this.lastQuery && field in this.lastQuery) {
|
|
12163
|
+
const q = { ...this.lastQuery };
|
|
12164
|
+
delete q[field];
|
|
12165
|
+
this.lastQuery = q;
|
|
12166
|
+
this.data.setQuery(q);
|
|
12167
|
+
}
|
|
12168
|
+
this.search$.next('');
|
|
12169
|
+
this.cdr.markForCheck();
|
|
11684
12170
|
}
|
|
11685
12171
|
isRemoteDataMode() {
|
|
11686
12172
|
const dataSource = this.config?.dataSource;
|
|
@@ -11773,6 +12259,7 @@ class PraxisList {
|
|
|
11773
12259
|
if (signature === this.lastRuntimeQueryContextSignature)
|
|
11774
12260
|
return;
|
|
11775
12261
|
this.lastRuntimeQueryContextSignature = signature;
|
|
12262
|
+
this.quickViewService?.dismiss('anchor-invalid');
|
|
11776
12263
|
this.lastQuery = nextQuery;
|
|
11777
12264
|
this.data.setQuery(nextQuery);
|
|
11778
12265
|
if (normalized?.sort?.length) {
|
|
@@ -11796,8 +12283,28 @@ class PraxisList {
|
|
|
11796
12283
|
if (plan.diagnostics.some((item) => item.level === 'error')) {
|
|
11797
12284
|
return;
|
|
11798
12285
|
}
|
|
12286
|
+
const prevResourcePath = String(this.appliedRuntimeConfig?.dataSource?.resourcePath || '')
|
|
12287
|
+
.trim()
|
|
12288
|
+
.replace(/^\/+|\/+$/g, '')
|
|
12289
|
+
.replace(/^api\//i, '')
|
|
12290
|
+
.toLowerCase();
|
|
12291
|
+
const nextConfig = normalizeListConfig(plan.canonicalConfig);
|
|
12292
|
+
const nextResourcePath = String(nextConfig?.dataSource?.resourcePath || '')
|
|
12293
|
+
.trim()
|
|
12294
|
+
.replace(/^\/+|\/+$/g, '')
|
|
12295
|
+
.replace(/^api\//i, '')
|
|
12296
|
+
.toLowerCase();
|
|
12297
|
+
if (prevResourcePath.length > 0 &&
|
|
12298
|
+
nextResourcePath.length > 0 &&
|
|
12299
|
+
prevResourcePath !== nextResourcePath) {
|
|
12300
|
+
this.activeSearchTerm = '';
|
|
12301
|
+
if (this.searchInputRef?.nativeElement) {
|
|
12302
|
+
this.searchInputRef.nativeElement.value = '';
|
|
12303
|
+
}
|
|
12304
|
+
this.expandedItemKeys = new Set();
|
|
12305
|
+
}
|
|
11799
12306
|
this.initializeDataStreams();
|
|
11800
|
-
this.config =
|
|
12307
|
+
this.config = nextConfig;
|
|
11801
12308
|
this.appliedRuntimeConfig = this.config;
|
|
11802
12309
|
this.syncPaginatorIntl();
|
|
11803
12310
|
this.syncExpansionState();
|
|
@@ -11822,9 +12329,6 @@ class PraxisList {
|
|
|
11822
12329
|
});
|
|
11823
12330
|
}
|
|
11824
12331
|
}
|
|
11825
|
-
if (plan.runtime?.schemaInference) {
|
|
11826
|
-
this.executeSchemaInferenceForPlan(plan.runtime.schemaInference, plan.persistence?.saveConfig === true);
|
|
11827
|
-
}
|
|
11828
12332
|
if (plan.runtime?.markForCheck) {
|
|
11829
12333
|
this.cdr.markForCheck();
|
|
11830
12334
|
}
|
|
@@ -11835,6 +12339,11 @@ class PraxisList {
|
|
|
11835
12339
|
inputPatch: { config: normalizeListConfig(plan.canonicalConfig) },
|
|
11836
12340
|
});
|
|
11837
12341
|
}
|
|
12342
|
+
if (plan.runtime?.schemaInference) {
|
|
12343
|
+
this.executeSchemaInferenceForPlan(plan.runtime.schemaInference, plan.persistence?.saveConfig === true, trigger === 'settings-applied' ||
|
|
12344
|
+
trigger === 'settings-saved' ||
|
|
12345
|
+
trigger === 'adapter');
|
|
12346
|
+
}
|
|
11838
12347
|
}
|
|
11839
12348
|
storageKey() {
|
|
11840
12349
|
if (this.configPersistenceStrategy === 'volatile') {
|
|
@@ -11861,33 +12370,59 @@ class PraxisList {
|
|
|
11861
12370
|
crud = inject(GenericCrudService, {
|
|
11862
12371
|
optional: true,
|
|
11863
12372
|
});
|
|
11864
|
-
|
|
12373
|
+
resourceDiscovery = inject(ResourceDiscoveryService, {
|
|
12374
|
+
optional: true,
|
|
12375
|
+
});
|
|
12376
|
+
executeSchemaInferenceForPlan(inferencePlan, saveAfterInference = false, publishAuthoringPatch = false) {
|
|
11865
12377
|
const resourcePath = inferencePlan.resourcePath;
|
|
11866
|
-
|
|
12378
|
+
const canDiscover = typeof this.resourceDiscovery?.getResourceSchemaFields === 'function' &&
|
|
12379
|
+
(typeof this.resourceDiscovery.canResolveSchemas !== 'function' ||
|
|
12380
|
+
this.resourceDiscovery.canResolveSchemas());
|
|
12381
|
+
if (!resourcePath || (!this.crud && !canDiscover))
|
|
11867
12382
|
return;
|
|
11868
|
-
|
|
12383
|
+
const inferenceTrigger = saveAfterInference
|
|
12384
|
+
? 'settings-saved'
|
|
12385
|
+
: publishAuthoringPatch
|
|
12386
|
+
? 'settings-applied'
|
|
12387
|
+
: 'schema-inference';
|
|
12388
|
+
const cachedNames = this.schemaFieldsByPath.get(resourcePath);
|
|
12389
|
+
if (this.inferredForPath.has(resourcePath) && cachedNames?.length) {
|
|
12390
|
+
const inferredDocument = inferListAuthoringDocument(inferencePlan.sourceDocument, { schemaFieldNames: cachedNames });
|
|
12391
|
+
if (JSON.stringify(inferredDocument.config) !==
|
|
12392
|
+
JSON.stringify(inferencePlan.sourceDocument.config)) {
|
|
12393
|
+
this.applyAuthoringPayload(inferredDocument, inferenceTrigger);
|
|
12394
|
+
}
|
|
11869
12395
|
return;
|
|
12396
|
+
}
|
|
11870
12397
|
if (this.schemaInferenceInFlight.has(resourcePath))
|
|
11871
12398
|
return;
|
|
11872
12399
|
this.schemaInferenceInFlight.add(resourcePath);
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
.
|
|
12400
|
+
const applyInferredFields = (fields) => {
|
|
12401
|
+
const names = (fields || [])
|
|
12402
|
+
.map((field) => field?.name || field?.field || field?.key)
|
|
12403
|
+
.filter(Boolean);
|
|
12404
|
+
if (!names.length)
|
|
12405
|
+
return false;
|
|
12406
|
+
this.inferredForPath.add(resourcePath);
|
|
12407
|
+
this.schemaFieldsByPath.set(resourcePath, names);
|
|
12408
|
+
const inferredDocument = inferListAuthoringDocument(inferencePlan.sourceDocument, {
|
|
12409
|
+
schemaFieldNames: names,
|
|
12410
|
+
});
|
|
12411
|
+
this.applyAuthoringPayload(inferredDocument, inferenceTrigger);
|
|
12412
|
+
return true;
|
|
12413
|
+
};
|
|
12414
|
+
const tryDiscoveryFallback = () => {
|
|
12415
|
+
if (!canDiscover || !this.resourceDiscovery) {
|
|
12416
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12417
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12418
|
+
return;
|
|
12419
|
+
}
|
|
12420
|
+
this.resourceDiscovery
|
|
12421
|
+
.getResourceSchemaFields(resourcePath)
|
|
11877
12422
|
.pipe(take(1))
|
|
11878
12423
|
.subscribe({
|
|
11879
12424
|
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');
|
|
12425
|
+
applyInferredFields(fields);
|
|
11891
12426
|
},
|
|
11892
12427
|
error: () => {
|
|
11893
12428
|
this.schemaInferenceInFlight.delete(resourcePath);
|
|
@@ -11897,10 +12432,78 @@ class PraxisList {
|
|
|
11897
12432
|
this.schemaInferenceInFlight.delete(resourcePath);
|
|
11898
12433
|
},
|
|
11899
12434
|
});
|
|
12435
|
+
};
|
|
12436
|
+
const tryCrudFallback = () => {
|
|
12437
|
+
if (!this.crud) {
|
|
12438
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12439
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12440
|
+
return;
|
|
12441
|
+
}
|
|
12442
|
+
try {
|
|
12443
|
+
this.crud.configure(resourcePath);
|
|
12444
|
+
this.crud
|
|
12445
|
+
.getSchema()
|
|
12446
|
+
.pipe(take(1))
|
|
12447
|
+
.subscribe({
|
|
12448
|
+
next: (crudFields) => applyInferredFields(crudFields),
|
|
12449
|
+
error: () => {
|
|
12450
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12451
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12452
|
+
},
|
|
12453
|
+
complete: () => {
|
|
12454
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12455
|
+
},
|
|
12456
|
+
});
|
|
12457
|
+
}
|
|
12458
|
+
catch {
|
|
12459
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12460
|
+
this.schemaFieldsByPath.delete(resourcePath);
|
|
12461
|
+
}
|
|
12462
|
+
};
|
|
12463
|
+
const isCatalogResourceKey = !resourcePath.includes('/') && resourcePath.includes('.');
|
|
12464
|
+
if (isCatalogResourceKey && canDiscover && this.resourceDiscovery) {
|
|
12465
|
+
this.resourceDiscovery
|
|
12466
|
+
.getResourceSchemaFields(resourcePath)
|
|
12467
|
+
.pipe(take(1))
|
|
12468
|
+
.subscribe({
|
|
12469
|
+
next: (fields) => {
|
|
12470
|
+
if (!applyInferredFields(fields)) {
|
|
12471
|
+
tryCrudFallback();
|
|
12472
|
+
}
|
|
12473
|
+
else {
|
|
12474
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12475
|
+
}
|
|
12476
|
+
},
|
|
12477
|
+
error: () => {
|
|
12478
|
+
tryCrudFallback();
|
|
12479
|
+
},
|
|
12480
|
+
});
|
|
12481
|
+
return;
|
|
12482
|
+
}
|
|
12483
|
+
try {
|
|
12484
|
+
if (!this.crud) {
|
|
12485
|
+
tryDiscoveryFallback();
|
|
12486
|
+
return;
|
|
12487
|
+
}
|
|
12488
|
+
this.crud.configure(resourcePath);
|
|
12489
|
+
this.crud
|
|
12490
|
+
.getSchema()
|
|
12491
|
+
.pipe(take(1))
|
|
12492
|
+
.subscribe({
|
|
12493
|
+
next: (fields) => {
|
|
12494
|
+
if (!applyInferredFields(fields)) {
|
|
12495
|
+
tryDiscoveryFallback();
|
|
12496
|
+
return;
|
|
12497
|
+
}
|
|
12498
|
+
this.schemaInferenceInFlight.delete(resourcePath);
|
|
12499
|
+
},
|
|
12500
|
+
error: () => {
|
|
12501
|
+
tryDiscoveryFallback();
|
|
12502
|
+
},
|
|
12503
|
+
});
|
|
11900
12504
|
}
|
|
11901
12505
|
catch {
|
|
11902
|
-
|
|
11903
|
-
this.schemaFieldsByPath.delete(resourcePath);
|
|
12506
|
+
tryDiscoveryFallback();
|
|
11904
12507
|
}
|
|
11905
12508
|
}
|
|
11906
12509
|
evalSlot(slot, item) {
|
|
@@ -12066,6 +12669,7 @@ class PraxisList {
|
|
|
12066
12669
|
}
|
|
12067
12670
|
}
|
|
12068
12671
|
catch { }
|
|
12672
|
+
const chipQuickView = normalizeResourceQuickViewBinding(def.quickView);
|
|
12069
12673
|
return {
|
|
12070
12674
|
type: def.type,
|
|
12071
12675
|
value,
|
|
@@ -12073,6 +12677,7 @@ class PraxisList {
|
|
|
12073
12677
|
style: def.style,
|
|
12074
12678
|
color,
|
|
12075
12679
|
variant: def.variant,
|
|
12680
|
+
...(chipQuickView ? { quickView: chipQuickView, sourceRecord: item } : {}),
|
|
12076
12681
|
};
|
|
12077
12682
|
}
|
|
12078
12683
|
if (def.type === 'icon') {
|
|
@@ -12642,6 +13247,9 @@ class PraxisList {
|
|
|
12642
13247
|
...def,
|
|
12643
13248
|
props: def.props ? JSON.parse(JSON.stringify(def.props)) : undefined,
|
|
12644
13249
|
badge: def.badge ? { ...def.badge } : undefined,
|
|
13250
|
+
quickView: def.quickView
|
|
13251
|
+
? JSON.parse(JSON.stringify(def.quickView))
|
|
13252
|
+
: undefined,
|
|
12645
13253
|
};
|
|
12646
13254
|
}
|
|
12647
13255
|
mergeTemplateDefs(base, override) {
|
|
@@ -12661,6 +13269,7 @@ class PraxisList {
|
|
|
12661
13269
|
merged.variant = overrideClone.variant ?? merged.variant;
|
|
12662
13270
|
merged.imageAlt = overrideClone.imageAlt ?? merged.imageAlt;
|
|
12663
13271
|
merged.badge = overrideClone.badge ?? merged.badge;
|
|
13272
|
+
merged.quickView = overrideClone.quickView ?? merged.quickView;
|
|
12664
13273
|
merged.props = this.mergePlainObjects(merged.props, overrideClone.props);
|
|
12665
13274
|
return merged;
|
|
12666
13275
|
}
|
|
@@ -12930,7 +13539,7 @@ class PraxisList {
|
|
|
12930
13539
|
ListDataService,
|
|
12931
13540
|
MatPaginatorIntl,
|
|
12932
13541
|
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 });
|
|
13542
|
+
], 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 span{font-weight:600;background-image:var(--pdx-text-shimmer-gradient, linear-gradient(105deg, var(--md-sys-color-on-surface-variant) 0%, var(--md-sys-color-on-surface-variant) 28%, var(--md-sys-color-primary) 44%, var(--md-sys-color-tertiary) 56%, var(--md-sys-color-on-surface-variant) 72%, var(--md-sys-color-on-surface-variant) 100%));background-size:260% 100%;background-position:200% 50%;-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;animation:praxis-list-loading-shimmer var(--pdx-text-shimmer-duration, 2.4s) linear infinite}@media(prefers-reduced-motion:reduce),(forced-colors:active),print{.list-loading-status span{animation:none;background-image:none;color:var(--pdx-text-shimmer-fallback-color, var(--md-sys-color-on-surface));-webkit-text-fill-color:currentColor}}@media(forced-colors:active){.list-loading-status span{color:CanvasText!important;-webkit-text-fill-color:CanvasText!important}}@keyframes praxis-list-loading-shimmer{0%{background-position:200% 50%}to{background-position:-60% 50%}}.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
13543
|
}
|
|
12935
13544
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisList, decorators: [{
|
|
12936
13545
|
type: Component,
|
|
@@ -12955,10 +13564,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
12955
13564
|
MatInputModule,
|
|
12956
13565
|
MatTooltipModule,
|
|
12957
13566
|
PraxisAiAssistantShellComponent,
|
|
13567
|
+
EmptyStateCardComponent,
|
|
12958
13568
|
ExecutiveBadgeComponent,
|
|
12959
13569
|
ExecutiveAlertsComponent,
|
|
12960
13570
|
ExecutiveOwnerComponent,
|
|
12961
13571
|
PraxisRichContent,
|
|
13572
|
+
PraxisQuickViewTriggerDirective,
|
|
12962
13573
|
PraxisListMetricComponent,
|
|
12963
13574
|
PraxisListComposeComponent,
|
|
12964
13575
|
PraxisListRuntimeComponentComponent,
|
|
@@ -12968,7 +13579,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
12968
13579
|
ListDataService,
|
|
12969
13580
|
MatPaginatorIntl,
|
|
12970
13581
|
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"] }]
|
|
13582
|
+
], 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 span{font-weight:600;background-image:var(--pdx-text-shimmer-gradient, linear-gradient(105deg, var(--md-sys-color-on-surface-variant) 0%, var(--md-sys-color-on-surface-variant) 28%, var(--md-sys-color-primary) 44%, var(--md-sys-color-tertiary) 56%, var(--md-sys-color-on-surface-variant) 72%, var(--md-sys-color-on-surface-variant) 100%));background-size:260% 100%;background-position:200% 50%;-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;animation:praxis-list-loading-shimmer var(--pdx-text-shimmer-duration, 2.4s) linear infinite}@media(prefers-reduced-motion:reduce),(forced-colors:active),print{.list-loading-status span{animation:none;background-image:none;color:var(--pdx-text-shimmer-fallback-color, var(--md-sys-color-on-surface));-webkit-text-fill-color:currentColor}}@media(forced-colors:active){.list-loading-status span{color:CanvasText!important;-webkit-text-fill-color:CanvasText!important}}@keyframes praxis-list-loading-shimmer{0%{background-position:200% 50%}to{background-position:-60% 50%}}.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
13583
|
}], propDecorators: { config: [{
|
|
12973
13584
|
type: Input
|
|
12974
13585
|
}], listId: [{
|
|
@@ -12997,7 +13608,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
12997
13608
|
type: Output
|
|
12998
13609
|
}], exportAction: [{
|
|
12999
13610
|
type: Output
|
|
13000
|
-
}], configPatchChange: [{ type: i0.Output, args: ["configPatchChange"] }]
|
|
13611
|
+
}], configPatchChange: [{ type: i0.Output, args: ["configPatchChange"] }], searchInputRef: [{
|
|
13612
|
+
type: ViewChild,
|
|
13613
|
+
args: ['searchInput']
|
|
13614
|
+
}] } });
|
|
13001
13615
|
|
|
13002
13616
|
class PraxisListSkinPreviewComponent {
|
|
13003
13617
|
skin;
|
|
@@ -14048,17 +14662,66 @@ class PraxisListConfigEditor {
|
|
|
14048
14662
|
if (!name)
|
|
14049
14663
|
continue;
|
|
14050
14664
|
names.push(name);
|
|
14665
|
+
const type = f.type ? f.type.trim() : undefined;
|
|
14666
|
+
const domainMeta = this.extractFieldDomainMeta(f, type);
|
|
14051
14667
|
nextMeta[name] = {
|
|
14052
14668
|
name,
|
|
14053
14669
|
...(f.label ? { label: f.label.trim() } : {}),
|
|
14054
|
-
...(
|
|
14670
|
+
...(type ? { type } : {}),
|
|
14055
14671
|
...(f.description ? { description: f.description.trim() } : {}),
|
|
14672
|
+
...(domainMeta.enumValues?.length ? { enumValues: domainMeta.enumValues } : {}),
|
|
14673
|
+
...(domainMeta.optionLabels ? { optionLabels: domainMeta.optionLabels } : {}),
|
|
14056
14674
|
};
|
|
14057
14675
|
}
|
|
14058
14676
|
this.fieldMetaByName = nextMeta;
|
|
14059
14677
|
this.fields = names;
|
|
14060
14678
|
}
|
|
14061
14679
|
}
|
|
14680
|
+
extractFieldDomainMeta(rawField, fallbackType) {
|
|
14681
|
+
if (!rawField || typeof rawField !== 'object') {
|
|
14682
|
+
return {};
|
|
14683
|
+
}
|
|
14684
|
+
const f = rawField;
|
|
14685
|
+
const rawOptions = f['enumValues'] ??
|
|
14686
|
+
f['enum'] ??
|
|
14687
|
+
f['options'] ??
|
|
14688
|
+
(f['uiConfig'] && typeof f['uiConfig'] === 'object'
|
|
14689
|
+
? f['uiConfig']['options']
|
|
14690
|
+
: undefined);
|
|
14691
|
+
const enumValues = [];
|
|
14692
|
+
const seen = new Set();
|
|
14693
|
+
const optionLabels = {};
|
|
14694
|
+
if (Array.isArray(rawOptions)) {
|
|
14695
|
+
for (const item of rawOptions) {
|
|
14696
|
+
if (typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean') {
|
|
14697
|
+
const key = String(item).trim();
|
|
14698
|
+
if (key && !seen.has(key)) {
|
|
14699
|
+
seen.add(key);
|
|
14700
|
+
enumValues.push(key);
|
|
14701
|
+
}
|
|
14702
|
+
}
|
|
14703
|
+
else if (item && typeof item === 'object') {
|
|
14704
|
+
const rec = item;
|
|
14705
|
+
const key = String(rec['value'] ?? rec['key'] ?? rec['id'] ?? rec['code'] ?? '').trim();
|
|
14706
|
+
const label = String(rec['label'] ?? rec['text'] ?? rec['description'] ?? '').trim();
|
|
14707
|
+
if (key && !seen.has(key)) {
|
|
14708
|
+
seen.add(key);
|
|
14709
|
+
enumValues.push(key);
|
|
14710
|
+
}
|
|
14711
|
+
if (key && label && label !== key) {
|
|
14712
|
+
optionLabels[key] = label;
|
|
14713
|
+
}
|
|
14714
|
+
}
|
|
14715
|
+
}
|
|
14716
|
+
}
|
|
14717
|
+
if (enumValues.length === 0 && String(fallbackType || '').trim().toLowerCase() === 'boolean') {
|
|
14718
|
+
enumValues.push('true', 'false');
|
|
14719
|
+
}
|
|
14720
|
+
return {
|
|
14721
|
+
...(enumValues.length > 0 ? { enumValues } : {}),
|
|
14722
|
+
...(Object.keys(optionLabels).length > 0 ? { optionLabels } : {}),
|
|
14723
|
+
};
|
|
14724
|
+
}
|
|
14062
14725
|
getFieldLabel(fieldName) {
|
|
14063
14726
|
const key = String(fieldName ?? '').trim();
|
|
14064
14727
|
if (!key)
|
|
@@ -14392,6 +15055,11 @@ class PraxisListConfigEditor {
|
|
|
14392
15055
|
});
|
|
14393
15056
|
this.document = document;
|
|
14394
15057
|
this.working = document.config;
|
|
15058
|
+
this.lastNonEmptyResourcePath = String(this.working?.dataSource?.resourcePath ?? '')
|
|
15059
|
+
.trim()
|
|
15060
|
+
.replace(/^\/+|\/+$/g, '')
|
|
15061
|
+
.replace(/^api\//i, '')
|
|
15062
|
+
.toLowerCase();
|
|
14395
15063
|
this.resetVisualMappingState();
|
|
14396
15064
|
this.hydrateMappingFromTemplating(this.working.templating);
|
|
14397
15065
|
this.hydrateUiEditorFromConfig();
|
|
@@ -14553,11 +15221,19 @@ class PraxisListConfigEditor {
|
|
|
14553
15221
|
f?.hint ||
|
|
14554
15222
|
cat?.description ||
|
|
14555
15223
|
'').trim();
|
|
15224
|
+
const primaryDomain = this.extractFieldDomainMeta(f, type);
|
|
15225
|
+
const fallbackDomain = !primaryDomain.enumValues?.length && cat
|
|
15226
|
+
? this.extractFieldDomainMeta(cat, type)
|
|
15227
|
+
: undefined;
|
|
15228
|
+
const enumValues = primaryDomain.enumValues ?? fallbackDomain?.enumValues;
|
|
15229
|
+
const optionLabels = primaryDomain.optionLabels ?? fallbackDomain?.optionLabels;
|
|
14556
15230
|
nextMeta[name] = {
|
|
14557
15231
|
name,
|
|
14558
15232
|
...(label ? { label } : {}),
|
|
14559
15233
|
...(type ? { type } : {}),
|
|
14560
15234
|
...(description ? { description } : {}),
|
|
15235
|
+
...(enumValues?.length ? { enumValues } : {}),
|
|
15236
|
+
...(optionLabels ? { optionLabels } : {}),
|
|
14561
15237
|
};
|
|
14562
15238
|
}
|
|
14563
15239
|
this.fieldMetaByName = nextMeta;
|
|
@@ -14598,9 +15274,30 @@ class PraxisListConfigEditor {
|
|
|
14598
15274
|
]
|
|
14599
15275
|
.map((field) => String(field ?? '').trim())
|
|
14600
15276
|
.filter(Boolean);
|
|
14601
|
-
|
|
15277
|
+
if (mappedDataFields.some((field) => !validFields.has(field))) {
|
|
15278
|
+
return true;
|
|
15279
|
+
}
|
|
15280
|
+
const templateRefs = new Set();
|
|
15281
|
+
const collectRefs = (val) => {
|
|
15282
|
+
if (typeof val === 'string') {
|
|
15283
|
+
for (const match of val.matchAll(/\$\{item\.([A-Za-z_][\w]*)(?:\|[^}]*)?\}/g)) {
|
|
15284
|
+
templateRefs.add(match[1]);
|
|
15285
|
+
}
|
|
15286
|
+
return;
|
|
15287
|
+
}
|
|
15288
|
+
if (!val || typeof val !== 'object')
|
|
15289
|
+
return;
|
|
15290
|
+
if (Array.isArray(val)) {
|
|
15291
|
+
val.forEach(collectRefs);
|
|
15292
|
+
return;
|
|
15293
|
+
}
|
|
15294
|
+
Object.values(val).forEach(collectRefs);
|
|
15295
|
+
};
|
|
15296
|
+
collectRefs(this.working?.templating);
|
|
15297
|
+
return Array.from(templateRefs).some((field) => !validFields.has(field));
|
|
14602
15298
|
}
|
|
14603
15299
|
pendingRemoteSlotInference = false;
|
|
15300
|
+
lastNonEmptyResourcePath = '';
|
|
14604
15301
|
syncSchemaFieldsFromWorking(immediate = false) {
|
|
14605
15302
|
const resourcePath = this.getActiveDataSourceMode() === 'remote'
|
|
14606
15303
|
? String(this.working?.dataSource?.resourcePath || '').trim()
|
|
@@ -14626,9 +15323,33 @@ class PraxisListConfigEditor {
|
|
|
14626
15323
|
});
|
|
14627
15324
|
}
|
|
14628
15325
|
onResourcePathChange(value) {
|
|
15326
|
+
const prevNormalized = this.lastNonEmptyResourcePath;
|
|
15327
|
+
const nextNormalized = String(value ?? '')
|
|
15328
|
+
.trim()
|
|
15329
|
+
.replace(/^\/+|\/+$/g, '')
|
|
15330
|
+
.replace(/^api\//i, '')
|
|
15331
|
+
.toLowerCase();
|
|
14629
15332
|
if (this.working?.dataSource) {
|
|
14630
15333
|
this.working.dataSource.resourcePath = value;
|
|
14631
15334
|
}
|
|
15335
|
+
if (nextNormalized.length === 0) {
|
|
15336
|
+
this.fields = [];
|
|
15337
|
+
this.fieldMetaByName = {};
|
|
15338
|
+
}
|
|
15339
|
+
else if (prevNormalized !== nextNormalized) {
|
|
15340
|
+
this.lastNonEmptyResourcePath = nextNormalized;
|
|
15341
|
+
if (prevNormalized.length > 0) {
|
|
15342
|
+
this.fields = [];
|
|
15343
|
+
this.fieldMetaByName = {};
|
|
15344
|
+
if (this.working?.dataSource) {
|
|
15345
|
+
delete this.working.dataSource.query;
|
|
15346
|
+
delete this.working.dataSource.sort;
|
|
15347
|
+
}
|
|
15348
|
+
this.queryJson = '';
|
|
15349
|
+
this.queryError = '';
|
|
15350
|
+
this.sortField = undefined;
|
|
15351
|
+
}
|
|
15352
|
+
}
|
|
14632
15353
|
this.resourcePathChanges.next({
|
|
14633
15354
|
path: String(value ?? '').trim(),
|
|
14634
15355
|
immediate: false,
|
|
@@ -14932,7 +15653,74 @@ class PraxisListConfigEditor {
|
|
|
14932
15653
|
target.locale = locale;
|
|
14933
15654
|
this.onMappingChanged();
|
|
14934
15655
|
}
|
|
15656
|
+
resolveStatusDomainField(explicitField) {
|
|
15657
|
+
if (this.getActiveDataSourceMode() === 'local') {
|
|
15658
|
+
return undefined;
|
|
15659
|
+
}
|
|
15660
|
+
const candidates = [
|
|
15661
|
+
explicitField,
|
|
15662
|
+
this.mappingTrailing?.field,
|
|
15663
|
+
this.mappingMeta?.type === 'chip' || this.mappingMeta?.type === 'icon'
|
|
15664
|
+
? this.mappingMeta?.field
|
|
15665
|
+
: undefined,
|
|
15666
|
+
this.mappingLeading?.type === 'chip' || this.mappingLeading?.type === 'icon'
|
|
15667
|
+
? this.mappingLeading?.field
|
|
15668
|
+
: undefined,
|
|
15669
|
+
]
|
|
15670
|
+
.map((f) => String(f ?? '').trim())
|
|
15671
|
+
.filter(Boolean);
|
|
15672
|
+
for (const candidate of candidates) {
|
|
15673
|
+
if (this.fieldMetaByName[candidate]?.enumValues?.length) {
|
|
15674
|
+
return candidate;
|
|
15675
|
+
}
|
|
15676
|
+
}
|
|
15677
|
+
const statusPattern = /(status|situacao|state|ativo|active|fase|etapa|stage|prioridade|priority|risco|risk|severidade|severity)/i;
|
|
15678
|
+
return this.fields.find((f) => statusPattern.test(f) && !!this.fieldMetaByName[f]?.enumValues?.length);
|
|
15679
|
+
}
|
|
15680
|
+
inferSemanticStatusColor(value, index) {
|
|
15681
|
+
const normalized = String(value ?? '')
|
|
15682
|
+
.normalize('NFD')
|
|
15683
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
15684
|
+
.trim()
|
|
15685
|
+
.toLowerCase();
|
|
15686
|
+
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)) {
|
|
15687
|
+
return 'warn';
|
|
15688
|
+
}
|
|
15689
|
+
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)) {
|
|
15690
|
+
return 'accent';
|
|
15691
|
+
}
|
|
15692
|
+
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)) {
|
|
15693
|
+
return 'primary';
|
|
15694
|
+
}
|
|
15695
|
+
const cycle = ['primary', 'accent', 'warn'];
|
|
15696
|
+
return cycle[index % cycle.length];
|
|
15697
|
+
}
|
|
15698
|
+
resolveDomainColorMapEntries(explicitField) {
|
|
15699
|
+
const field = this.resolveStatusDomainField(explicitField);
|
|
15700
|
+
const values = field ? this.fieldMetaByName[field]?.enumValues : undefined;
|
|
15701
|
+
if (!values?.length) {
|
|
15702
|
+
return [];
|
|
15703
|
+
}
|
|
15704
|
+
return values.map((key, index) => ({
|
|
15705
|
+
key,
|
|
15706
|
+
color: this.inferSemanticStatusColor(key, index),
|
|
15707
|
+
}));
|
|
15708
|
+
}
|
|
15709
|
+
resolveDomainLabelMapEntries(explicitField) {
|
|
15710
|
+
const field = this.resolveStatusDomainField(explicitField);
|
|
15711
|
+
const labels = field ? this.fieldMetaByName[field]?.optionLabels : undefined;
|
|
15712
|
+
if (!labels) {
|
|
15713
|
+
return [];
|
|
15714
|
+
}
|
|
15715
|
+
return Object.entries(labels)
|
|
15716
|
+
.filter(([key, label]) => !!key.trim() && !!label.trim())
|
|
15717
|
+
.map(([key, label]) => ({ key: key.trim(), label: label.trim() }));
|
|
15718
|
+
}
|
|
14935
15719
|
defaultStatusColorMapEntries() {
|
|
15720
|
+
const domainEntries = this.resolveDomainColorMapEntries();
|
|
15721
|
+
if (domainEntries.length > 0) {
|
|
15722
|
+
return domainEntries;
|
|
15723
|
+
}
|
|
14936
15724
|
const locale = this.defaultPresetLocale().toLowerCase();
|
|
14937
15725
|
if (locale.startsWith('pt')) {
|
|
14938
15726
|
return [
|
|
@@ -16238,6 +17026,19 @@ class PraxisListConfigEditor {
|
|
|
16238
17026
|
this.onMappingChanged();
|
|
16239
17027
|
}
|
|
16240
17028
|
applyStandardStatusColorMap() {
|
|
17029
|
+
const domainColors = this.resolveDomainColorMapEntries();
|
|
17030
|
+
if (domainColors.length > 0) {
|
|
17031
|
+
this.chipColorMapEntries = domainColors;
|
|
17032
|
+
this.onChipColorMapChanged();
|
|
17033
|
+
if (!this.chipLabelMapEntries || this.chipLabelMapEntries.length === 0) {
|
|
17034
|
+
const domainLabels = this.resolveDomainLabelMapEntries();
|
|
17035
|
+
if (domainLabels.length > 0) {
|
|
17036
|
+
this.chipLabelMapEntries = domainLabels;
|
|
17037
|
+
this.onChipLabelMapChanged();
|
|
17038
|
+
}
|
|
17039
|
+
}
|
|
17040
|
+
return;
|
|
17041
|
+
}
|
|
16241
17042
|
const locale = this.defaultPresetLocale().toLowerCase();
|
|
16242
17043
|
this.chipColorMapEntries = locale.startsWith('pt')
|
|
16243
17044
|
? [
|
|
@@ -17653,13 +18454,76 @@ class PraxisListConfigEditor {
|
|
|
17653
18454
|
}
|
|
17654
18455
|
// UI editor hydration already called in ctor
|
|
17655
18456
|
// Ensure UI.sortOptions are kept when saving via Settings Panel
|
|
18457
|
+
isGenericInferredChipColorMap(map) {
|
|
18458
|
+
if (!map)
|
|
18459
|
+
return true;
|
|
18460
|
+
const entries = Object.entries(map);
|
|
18461
|
+
if (entries.length === 0)
|
|
18462
|
+
return true;
|
|
18463
|
+
const genericDefaults = {
|
|
18464
|
+
ativo: 'primary',
|
|
18465
|
+
active: 'primary',
|
|
18466
|
+
true: 'primary',
|
|
18467
|
+
inativo: 'warn',
|
|
18468
|
+
inactive: 'warn',
|
|
18469
|
+
false: 'warn',
|
|
18470
|
+
};
|
|
18471
|
+
return (entries.length === Object.keys(genericDefaults).length &&
|
|
18472
|
+
entries.every(([k, v]) => genericDefaults[k] === v));
|
|
18473
|
+
}
|
|
18474
|
+
isGenericInferredChipLabelMap(map) {
|
|
18475
|
+
if (!map)
|
|
18476
|
+
return true;
|
|
18477
|
+
const entries = Object.entries(map);
|
|
18478
|
+
if (entries.length === 0)
|
|
18479
|
+
return true;
|
|
18480
|
+
const genericDefaults = {
|
|
18481
|
+
true: 'Ativo',
|
|
18482
|
+
false: 'Inativo',
|
|
18483
|
+
ativo: 'Ativo',
|
|
18484
|
+
inativo: 'Inativo',
|
|
18485
|
+
active: 'Ativo',
|
|
18486
|
+
inactive: 'Inativo',
|
|
18487
|
+
};
|
|
18488
|
+
return (entries.length === Object.keys(genericDefaults).length &&
|
|
18489
|
+
entries.every(([k, v]) => genericDefaults[k] === v));
|
|
18490
|
+
}
|
|
17656
18491
|
inferFromFields() {
|
|
17657
18492
|
if (!this.fields?.length)
|
|
17658
18493
|
return;
|
|
18494
|
+
const preTemplating = this.working?.templating;
|
|
18495
|
+
const validFields = new Set(this.fields);
|
|
18496
|
+
const prevTrailingField = String(this.mappingTrailing?.field ?? '').trim();
|
|
18497
|
+
const isPrevTrailingGrounded = !prevTrailingField || validFields.has(prevTrailingField);
|
|
18498
|
+
const hadCustomChipColorMap = isPrevTrailingGrounded &&
|
|
18499
|
+
!this.isGenericInferredChipColorMap(preTemplating?.chipColorMap);
|
|
18500
|
+
const hadCustomChipLabelMap = isPrevTrailingGrounded &&
|
|
18501
|
+
!this.isGenericInferredChipLabelMap(preTemplating?.chipLabelMap);
|
|
17659
18502
|
const inferred = inferListAuthoringDocument(this.buildCurrentDocument(), {
|
|
17660
18503
|
schemaFieldNames: this.fields,
|
|
17661
18504
|
});
|
|
17662
18505
|
this.applyIncomingDocument(inferred);
|
|
18506
|
+
const trailingField = this.mappingTrailing?.field;
|
|
18507
|
+
const isTrailingBoolean = !!trailingField &&
|
|
18508
|
+
this.fieldMetaByName[trailingField]?.type?.toLowerCase() === 'boolean';
|
|
18509
|
+
if (this.mappingTrailing?.type === 'chip' &&
|
|
18510
|
+
trailingField &&
|
|
18511
|
+
!isTrailingBoolean &&
|
|
18512
|
+
!hadCustomChipColorMap) {
|
|
18513
|
+
const domainColors = this.resolveDomainColorMapEntries(trailingField);
|
|
18514
|
+
if (domainColors.length > 0) {
|
|
18515
|
+
this.chipColorMapEntries = domainColors;
|
|
18516
|
+
if (!hadCustomChipLabelMap) {
|
|
18517
|
+
const domainLabels = this.resolveDomainLabelMapEntries(trailingField);
|
|
18518
|
+
if (domainLabels.length > 0) {
|
|
18519
|
+
this.chipLabelMapEntries = domainLabels;
|
|
18520
|
+
}
|
|
18521
|
+
}
|
|
18522
|
+
this.working = this.composeWorkingFromVisualState();
|
|
18523
|
+
this.mappingDirty = false;
|
|
18524
|
+
this.appliedMappingSnapshot = this.getMappingSnapshot();
|
|
18525
|
+
}
|
|
18526
|
+
}
|
|
17663
18527
|
this.markDirty();
|
|
17664
18528
|
this.verify();
|
|
17665
18529
|
}
|