@praxisui/dynamic-form 9.0.65 → 9.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, inject, HostListener, Output, Input, Component, Optional, Inject, Injector, effect, ViewChildren, ViewChild, ChangeDetectionStrategy, SimpleChange, ENVIRONMENT_INITIALIZER } from '@angular/core';
2
+ import { Injectable, EventEmitter, inject, HostListener, Output, Input, Component, Optional, Inject, Injector, effect, ViewChildren, ViewChild, ChangeDetectionStrategy, SimpleChange, ENVIRONMENT_INITIALIZER, ChangeDetectorRef } from '@angular/core';
3
3
  import * as i1$2 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i2 from '@angular/common/http';
@@ -1204,7 +1204,7 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1204
1204
  'config.tabs.schema': 'Verificação de Schema',
1205
1205
  'config.tabs.layout': 'Layout',
1206
1206
  'config.tabs.hooks': 'Hooks',
1207
- 'config.tabs.presentation': 'Modo Apresentação',
1207
+ 'config.tabs.presentation': 'Estilo da apresentação',
1208
1208
  'config.tabs.behavior': 'Comportamento',
1209
1209
  'config.tabs.hints': 'Dicas e Tooltips',
1210
1210
  'config.tabs.actions': 'Ações',
@@ -1214,16 +1214,33 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1214
1214
  'config.tabs.navigation': 'Navegação',
1215
1215
  'config.tabs.json': 'JSON',
1216
1216
  'config.common.understand': 'Entenda:',
1217
+ 'config.general.displayMode.pendingHint': 'Apresentação inativa: em Criar e Editar, os dados aparecem como campos para preenchimento. Mude para Visualizar para apresentar rótulos e valores.',
1218
+ 'config.general.displayMode.entryHint': 'Exibição: campos para preenchimento. A apresentação fica disponível ao visualizar os dados.',
1219
+ 'config.general.displayMode.readonlyHint': 'Exibição: campos somente para leitura. Para mostrar rótulos e valores, escolha Apresentação.',
1220
+ 'config.general.displayMode.automaticHint': 'Exibição definida pela configuração e pelos metadados do formulário. Escolha Campos ou Apresentação para definir uma preferência explícita.',
1221
+ 'config.general.displayMode.useView': 'Mudar para Visualizar',
1222
+ 'config.general.displayMode.openStyle': 'Configurar estilo da apresentação',
1223
+ 'config.general.pageSaveHint': 'Aplicar atualiza a prévia do widget. Salvar e fechar conclui esta edição. Para persistir a composição, use Salvar página.',
1224
+ 'config.presentation.preview.sampleHint': 'Exemplo ilustrativo de leitura; não altera os dados do formulário.',
1225
+ 'config.presentation.align.start': 'Alinhar ao início',
1226
+ 'config.presentation.align.center': 'Centralizar',
1227
+ 'config.presentation.align.end': 'Alinhar ao fim',
1217
1228
  'config.general.title': 'Dados do formulário',
1218
- 'config.general.subtitle': 'Defina o modo de dados e o contexto de edição.',
1229
+ 'config.general.subtitle': 'Escolha a operação e como os dados serão exibidos.',
1230
+ 'config.general.displayMode.label': 'Modo de exibição',
1231
+ 'config.general.displayMode.automatic': 'Automático',
1232
+ 'config.general.displayMode.fields': 'Campos',
1233
+ 'config.general.displayMode.presentation': 'Apresentação',
1234
+ 'config.general.displayMode.viewHint': 'Exibição: rótulos e valores para leitura, sem preenchimento.',
1235
+ 'config.general.displayMode.editHint': 'A apresentação só é aplicada em view. Em create e edit, os campos continuam disponíveis para preenchimento.',
1219
1236
  'config.general.inputMode.label': 'Modo de dados',
1220
- 'config.general.inputMode.create': 'create',
1221
- 'config.general.inputMode.edit': 'edit',
1222
- 'config.general.inputMode.view': 'view',
1237
+ 'config.general.inputMode.create': 'Criar',
1238
+ 'config.general.inputMode.edit': 'Editar',
1239
+ 'config.general.inputMode.view': 'Visualizar',
1223
1240
  'config.general.inputMode.tooltip': 'O mode controla o fluxo (create/edit/view). enableCustomization só libera edição do layout e não altera o mode.',
1224
- 'config.general.bindings.label': 'Bindings',
1225
- 'config.general.bindings.persisted': '`bindings.mode` será persistido no documento canônico.',
1226
- 'config.general.bindings.implicit': 'Bloco ausente no documento canônico. O valor exibido é fallback visual e não será salvo até você editar este campo.',
1241
+ 'config.general.bindings.label': 'Preferências iniciais',
1242
+ 'config.general.bindings.persisted': 'As escolhas explícitas serão salvas com o formulário.',
1243
+ 'config.general.bindings.implicit': 'O formulário usa os valores padrão. Edite uma opção para definir sua preferência.',
1227
1244
  'config.general.runtimeContract.title': 'Contrato Runtime Resolvido',
1228
1245
  'config.general.runtimeContract.subtitle': 'Visualização somente leitura do contrato backend resolvido pelo host atual.',
1229
1246
  'config.general.runtimeContract.runtimeLabel': 'Runtime',
@@ -1362,11 +1379,11 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1362
1379
  'dynamicForm.canvasToolbar.config.default': 'Configurar',
1363
1380
  'config.hooks.title': 'Hooks de ciclo de vida',
1364
1381
  'config.hooks.subtitle': 'Automatize ações nos eventos do formulário.',
1365
- 'config.presentation.title': 'Modo Apresentação',
1366
- 'config.presentation.subtitle': 'Configurações de exibição aplicadas somente ao modo apresentação.',
1367
- 'config.presentation.block.label': 'Presentation',
1368
- 'config.presentation.block.persisted': '`contextSnapshot.presentation` será persistido no documento canônico.',
1369
- 'config.presentation.block.implicit': 'Bloco ausente no documento canônico. A pré-visualização usa fallback local e não será salva até você editar.',
1382
+ 'config.presentation.title': 'Estilo da apresentação',
1383
+ 'config.presentation.subtitle': 'Ajuste a leitura dos rótulos e valores. A prévia usa dados de exemplo.',
1384
+ 'config.presentation.block.label': 'Preferências de estilo',
1385
+ 'config.presentation.block.persisted': 'Estes ajustes serão aplicados ao formulário.',
1386
+ 'config.presentation.block.implicit': 'Usando o estilo padrão. Altere uma opção para personalizar.',
1370
1387
  'config.presentation.labelPosition.label': 'Posição do rótulo',
1371
1388
  'config.presentation.labelPosition.ariaLabel': 'Posição do rótulo',
1372
1389
  'config.presentation.labelPosition.above': 'Acima',
@@ -1384,10 +1401,10 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1384
1401
  'config.presentation.labelFontSize.placeholder': 'ex.: 12',
1385
1402
  'config.presentation.valueFontSize.label': 'Tamanho do valor',
1386
1403
  'config.presentation.valueFontSize.placeholder': 'ex.: 16',
1387
- 'config.presentation.labelWidth.label': 'Largura do rótulo (label à esquerda)',
1404
+ 'config.presentation.labelWidth.label': 'Largura do rótulo lateral',
1388
1405
  'config.presentation.labelWidth.placeholder': 'ex.: 140',
1389
- 'config.presentation.options.compactMode': 'Modo compacto',
1390
- 'config.presentation.options.truncateValues': 'Truncar valores',
1406
+ 'config.presentation.options.compactMode': 'Compactar linhas e seções',
1407
+ 'config.presentation.options.truncateValues': 'Abreviar textos apenas na prévia',
1391
1408
  'config.presentation.preview.title': 'Pré-visualização',
1392
1409
  'config.presentation.preview.items.name.label': 'Nome',
1393
1410
  'config.presentation.preview.items.name.value': 'Maria da Conceição Albuquerque de Souza',
@@ -1702,7 +1719,7 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1702
1719
  'config.tabs.schema': 'Schema Verification',
1703
1720
  'config.tabs.layout': 'Layout',
1704
1721
  'config.tabs.hooks': 'Hooks',
1705
- 'config.tabs.presentation': 'Presentation Mode',
1722
+ 'config.tabs.presentation': 'Presentation style',
1706
1723
  'config.tabs.behavior': 'Behavior',
1707
1724
  'config.tabs.hints': 'Hints and Tooltips',
1708
1725
  'config.tabs.actions': 'Actions',
@@ -1712,16 +1729,33 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1712
1729
  'config.tabs.navigation': 'Navigation',
1713
1730
  'config.tabs.json': 'JSON',
1714
1731
  'config.common.understand': 'Understand:',
1732
+ 'config.general.displayMode.pendingHint': 'Presentation inactive: Create and Edit show fields for data entry. Switch to View to present labels and values.',
1733
+ 'config.general.displayMode.entryHint': 'Display: fields for data entry. Presentation becomes available when viewing data.',
1734
+ 'config.general.displayMode.readonlyHint': 'Display: read-only fields. Choose Presentation to show labels and values.',
1735
+ 'config.general.displayMode.automaticHint': 'Display follows the form configuration and metadata. Choose Fields or Presentation to set an explicit preference.',
1736
+ 'config.general.displayMode.useView': 'Switch to View',
1737
+ 'config.general.displayMode.openStyle': 'Configure presentation style',
1738
+ 'config.general.pageSaveHint': 'Apply updates the widget preview. Save and close finishes this edit. Use Save page to persist the composition.',
1739
+ 'config.presentation.preview.sampleHint': 'Illustrative reading sample; does not change form data.',
1740
+ 'config.presentation.align.start': 'Align to start',
1741
+ 'config.presentation.align.center': 'Align to center',
1742
+ 'config.presentation.align.end': 'Align to end',
1715
1743
  'config.general.title': 'Form data',
1716
- 'config.general.subtitle': 'Define the data mode and editing context.',
1744
+ 'config.general.subtitle': 'Choose the operation and how data will be displayed.',
1745
+ 'config.general.displayMode.label': 'Display mode',
1746
+ 'config.general.displayMode.automatic': 'Automatic',
1747
+ 'config.general.displayMode.fields': 'Fields',
1748
+ 'config.general.displayMode.presentation': 'Presentation',
1749
+ 'config.general.displayMode.viewHint': 'Display: labels and values for reading, without data entry.',
1750
+ 'config.general.displayMode.editHint': 'Presentation applies only in view mode. In create and edit, fields remain available for data entry.',
1717
1751
  'config.general.inputMode.label': 'Data mode',
1718
- 'config.general.inputMode.create': 'create',
1719
- 'config.general.inputMode.edit': 'edit',
1720
- 'config.general.inputMode.view': 'view',
1752
+ 'config.general.inputMode.create': 'Create',
1753
+ 'config.general.inputMode.edit': 'Edit',
1754
+ 'config.general.inputMode.view': 'View',
1721
1755
  'config.general.inputMode.tooltip': 'mode controls the flow (create/edit/view). enableCustomization only enables layout editing and does not change mode.',
1722
- 'config.general.bindings.label': 'Bindings',
1723
- 'config.general.bindings.persisted': '`bindings.mode` will be persisted in the canonical document.',
1724
- 'config.general.bindings.implicit': 'Block missing from the canonical document. The displayed value is a visual fallback and will not be saved until you edit this field.',
1756
+ 'config.general.bindings.label': 'Initial preferences',
1757
+ 'config.general.bindings.persisted': 'Explicit choices will be saved with the form.',
1758
+ 'config.general.bindings.implicit': 'The form uses default values. Edit an option to set your preference.',
1725
1759
  'config.general.runtimeContract.title': 'Resolved Runtime Contract',
1726
1760
  'config.general.runtimeContract.subtitle': 'Read-only view of the backend contract resolved by the current host.',
1727
1761
  'config.general.runtimeContract.runtimeLabel': 'Runtime',
@@ -1860,11 +1894,11 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1860
1894
  'dynamicForm.canvasToolbar.config.default': 'Configure',
1861
1895
  'config.hooks.title': 'Lifecycle hooks',
1862
1896
  'config.hooks.subtitle': 'Automate actions on form events.',
1863
- 'config.presentation.title': 'Presentation Mode',
1864
- 'config.presentation.subtitle': 'Display settings applied only to presentation mode.',
1865
- 'config.presentation.block.label': 'Presentation',
1866
- 'config.presentation.block.persisted': '`contextSnapshot.presentation` will be persisted in the canonical document.',
1867
- 'config.presentation.block.implicit': 'Block missing from the canonical document. The preview uses a local fallback and will not be saved until you edit.',
1897
+ 'config.presentation.title': 'Presentation style',
1898
+ 'config.presentation.subtitle': 'Adjust how labels and values are read. The preview uses sample data.',
1899
+ 'config.presentation.block.label': 'Style preferences',
1900
+ 'config.presentation.block.persisted': 'These settings will be applied to the form.',
1901
+ 'config.presentation.block.implicit': 'Using the default style. Change an option to customize it.',
1868
1902
  'config.presentation.labelPosition.label': 'Label position',
1869
1903
  'config.presentation.labelPosition.ariaLabel': 'Label position',
1870
1904
  'config.presentation.labelPosition.above': 'Above',
@@ -1882,10 +1916,10 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
1882
1916
  'config.presentation.labelFontSize.placeholder': 'e.g. 12',
1883
1917
  'config.presentation.valueFontSize.label': 'Value size',
1884
1918
  'config.presentation.valueFontSize.placeholder': 'e.g. 16',
1885
- 'config.presentation.labelWidth.label': 'Label width (left label)',
1919
+ 'config.presentation.labelWidth.label': 'Side label width',
1886
1920
  'config.presentation.labelWidth.placeholder': 'e.g. 140',
1887
- 'config.presentation.options.compactMode': 'Compact mode',
1888
- 'config.presentation.options.truncateValues': 'Truncate values',
1921
+ 'config.presentation.options.compactMode': 'Compact rows and sections',
1922
+ 'config.presentation.options.truncateValues': 'Shorten text in preview only',
1889
1923
  'config.presentation.preview.title': 'Preview',
1890
1924
  'config.presentation.preview.items.name.label': 'Name',
1891
1925
  'config.presentation.preview.items.name.value': 'Maria da Conceicao Albuquerque de Souza',
@@ -6614,6 +6648,8 @@ const PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST = {
6614
6648
  { name: 'emptyState', type: 'PraxisDynamicFormEmptyState', description: 'Placeholder opt-in para mode=view sem resourceId nem snapshot local; reutiliza o empty state compartilhado e mantém a mensagem de negócio no plano/host.' },
6615
6649
  { name: 'readUrl', type: 'string', description: 'Endpoint canonico de leitura para surfaces VIEW/READ_PROJECTION' },
6616
6650
  { name: 'mode', type: 'string', allowedValues: ['create', 'edit', 'view'], description: 'Modo de operação' },
6651
+ { name: 'presentation', type: 'DynamicFormPresentationSnapshot | null', description: 'Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal.' },
6652
+ { name: 'presentationModeGlobal', type: 'boolean | null', description: 'Preferência de exibição, também authorada em bindings.presentationModeGlobal: true apresenta rótulos e valores somente em mode=view; false força campos; null/ausência segue layoutPolicy. Não altera o modo dos dados.' },
6617
6653
  { name: 'configPersistenceStrategy', type: 'string', allowedValues: ['local-first', 'input-first'], description: 'Precedência entre configuração persistida e contrato explícito do host. Use input-first em dialogs e surfaces transitórias governadas por schema para preservar mode e estados operacionais publicados pelo servidor.' },
6618
6654
  { name: 'generatedLayoutPreset', type: 'string', allowedValues: ['default', 'compactPresentation'], description: 'Preset usado apenas ao gerar a configuracao inicial a partir de metadata/schema; nao reprocessa layouts persistidos ou autorados.' },
6619
6655
  { name: 'layoutPolicy', type: 'DynamicFormLayoutPolicy', description: 'Politica opt-in para layout schema-driven transient. Use source=schema apenas quando o backend schema for a fonte canonica do agrupamento; use detailSummary para seleção de campos e densidade responsiva do resumo read-only compacto sem FormConfig.sections locais. Quando o resumo precisar vencer x-ui.width publicado para outras surfaces, use detailSummary.widthPrecedence=summary. Em groupedCommand, orphanFieldExpansion governa linhas lógicas com um unico campo; partialRowStrategy=fill-compatible projeta spans compatíveis depois de resolver visibilidade responsiva, CSS order e wrap, sem alterar x-ui.width ou persistir sections; contextFields identifica campos do request hidratados pela surface que permanecem no payload sem criar controles redundantes.' },
@@ -8686,6 +8722,7 @@ function parseLegacyOrDynamicFormDocument(raw) {
8686
8722
  config: extractLegacyFormConfig(obj),
8687
8723
  bindings: {
8688
8724
  mode: normalizeMode(obj.inputsPatch?.mode),
8725
+ presentationModeGlobal: obj.inputsPatch?.presentationModeGlobal,
8689
8726
  },
8690
8727
  contextSnapshot: {
8691
8728
  backConfig: normalizeBackConfig(obj.backConfig),
@@ -8736,6 +8773,10 @@ function validateDynamicFormAuthoringInput(raw, context) {
8736
8773
  !VALID_MODES.includes(rawBindings.mode)) {
8737
8774
  diagnostics.push(errorDiagnostic('dynamicForm.bindings.mode.invalid', 'bindings.mode must be create, edit or view', 'bindings.mode'));
8738
8775
  }
8776
+ if (rawBindings.presentationModeGlobal != null &&
8777
+ typeof rawBindings.presentationModeGlobal !== 'boolean') {
8778
+ diagnostics.push(errorDiagnostic('dynamicForm.bindings.presentationModeGlobal.invalid', 'bindings.presentationModeGlobal must be boolean or null', 'bindings.presentationModeGlobal'));
8779
+ }
8739
8780
  const rawSchemaPrefs = asRecord(rawContextSnapshot.schemaPrefs);
8740
8781
  if (Object.prototype.hasOwnProperty.call(rawSchemaPrefs, 'notifyIfOutdated') &&
8741
8782
  rawSchemaPrefs.notifyIfOutdated != null &&
@@ -8878,6 +8919,8 @@ function buildDynamicFormApplyPlan(doc, runtime, options) {
8878
8919
  clearMode: options?.replaceContext === true &&
8879
8920
  !bindingsPatch?.mode &&
8880
8921
  !!runtime?.currentBindings?.mode,
8922
+ clearPresentationMode: options?.replaceContext === true &&
8923
+ bindingsPatch?.presentationModeGlobal === undefined,
8881
8924
  rebuildForm: true,
8882
8925
  refreshPresentation: !!contextSnapshot?.presentation,
8883
8926
  clearPresentation: options?.replaceContext === true &&
@@ -8984,6 +9027,8 @@ function normalizeBindings(bindings) {
8984
9027
  return undefined;
8985
9028
  return stripUndefinedShallow({
8986
9029
  mode: normalizeMode(bindings.mode),
9030
+ presentationModeGlobal: typeof bindings.presentationModeGlobal === 'boolean' || bindings.presentationModeGlobal === null
9031
+ ? bindings.presentationModeGlobal : undefined,
8987
9032
  });
8988
9033
  }
8989
9034
  function normalizeContextSnapshot(snapshot) {
@@ -11333,6 +11378,8 @@ class PraxisDynamicForm {
11333
11378
  readonlyModeGlobal = null;
11334
11379
  disabledModeGlobal = null;
11335
11380
  presentationModeGlobal = null;
11381
+ /** Projection of contextSnapshot.presentation; null clears authored style overrides. */
11382
+ presentation;
11336
11383
  visibleGlobal = null;
11337
11384
  fieldIconPolicy = 'all';
11338
11385
  /** Opt-in loader for shared domain rule materializations persisted outside FormConfig. */
@@ -11923,6 +11970,7 @@ class PraxisDynamicForm {
11923
11970
  if (!path)
11924
11971
  return;
11925
11972
  this.resourcePath = path;
11973
+ this.configPatchChange.emit({ inputPatch: { resourcePath: path } });
11926
11974
  this.saveConnection('quick-connect');
11927
11975
  this.configureCrudRuntime();
11928
11976
  if (!this.isInitialized && !this.isLoading && this.formId) {
@@ -12522,6 +12570,9 @@ class PraxisDynamicForm {
12522
12570
  if (this.configPersistenceStrategy !== 'input-first' &&
12523
12571
  inputsPref &&
12524
12572
  typeof inputsPref === 'object') {
12573
+ if (typeof inputsPref.presentationModeGlobal === 'boolean' || inputsPref.presentationModeGlobal === null) {
12574
+ this.presentationModeGlobal = inputsPref.presentationModeGlobal;
12575
+ }
12525
12576
  if (inputsPref.mode === 'create' || inputsPref.mode === 'edit' || inputsPref.mode === 'view') {
12526
12577
  this.mode = inputsPref.mode;
12527
12578
  this.debugLog('🔧 Applied persisted input mode', { mode: this.mode });
@@ -12711,6 +12762,10 @@ class PraxisDynamicForm {
12711
12762
  this.verifyServerSchemaVersion().catch(() => { });
12712
12763
  }
12713
12764
  }
12765
+ if (changes['presentation']) {
12766
+ this.resetPresentationVarsToDefaults();
12767
+ this.applyPresentationVars();
12768
+ }
12714
12769
  // Update resolved schema prefs when related @Inputs change
12715
12770
  if (changes['notifyIfOutdated'] || changes['snoozeMs'] || changes['autoOpenSettingsOnOutdated']) {
12716
12771
  try {
@@ -14531,7 +14586,7 @@ class PraxisDynamicForm {
14531
14586
  }
14532
14587
  isLastVisibleSection(section) {
14533
14588
  const visibleSections = (this.config.sections || []).filter((candidate) => this.isSectionVisible(candidate));
14534
- return visibleSections.at(-1) === section;
14589
+ return visibleSections[visibleSections.length - 1] === section;
14535
14590
  }
14536
14591
  hasVisibleSectionBody(section) {
14537
14592
  return Array.isArray(section.rows)
@@ -14552,7 +14607,7 @@ class PraxisDynamicForm {
14552
14607
  return candidate;
14553
14608
  }
14554
14609
  }
14555
- return eligibleSections.at(-1);
14610
+ return eligibleSections[eligibleSections.length - 1];
14556
14611
  }
14557
14612
  getSectionTitle(section) {
14558
14613
  const props = this.getSectionRuleProps(section);
@@ -16489,7 +16544,7 @@ class PraxisDynamicForm {
16489
16544
  const initialConfig = normalizeFormConfig$1(this.config);
16490
16545
  const initialDocument = createDynamicFormAuthoringDocument({
16491
16546
  config: initialConfig,
16492
- bindings: { mode: this.mode },
16547
+ bindings: { mode: this.mode, presentationModeGlobal: this.presentationModeGlobal },
16493
16548
  contextSnapshot: this.captureCurrentContextSnapshot(),
16494
16549
  });
16495
16550
  const { PraxisDynamicFormConfigEditor } = await Promise.resolve().then(function () { return index; });
@@ -16503,7 +16558,7 @@ class PraxisDynamicForm {
16503
16558
  document: initialDocument,
16504
16559
  formId: this.formId,
16505
16560
  componentKeyId: this.componentKeyId(),
16506
- presentationMode: this.presentationModeGlobal === true,
16561
+ presentationMode: this.effectivePresentation,
16507
16562
  runtimeContext: this.buildDynamicFormEditorRuntimeContext(),
16508
16563
  },
16509
16564
  },
@@ -19799,7 +19854,7 @@ class PraxisDynamicForm {
19799
19854
  ? parseLegacyOrDynamicFormDocument(nextConfig)
19800
19855
  : createDynamicFormAuthoringDocument({
19801
19856
  config: nextConfig,
19802
- bindings: { mode: this.mode },
19857
+ bindings: { mode: this.mode, presentationModeGlobal: this.presentationModeGlobal },
19803
19858
  contextSnapshot: this.captureCurrentContextSnapshot(),
19804
19859
  });
19805
19860
  const plan = buildDynamicFormApplyPlan(doc, this.buildDynamicFormEditorRuntimeContext(), {
@@ -19815,6 +19870,7 @@ class PraxisDynamicForm {
19815
19870
  return {
19816
19871
  currentBindings: {
19817
19872
  mode: this.mode,
19873
+ presentationModeGlobal: this.presentationModeGlobal,
19818
19874
  },
19819
19875
  currentContextSnapshot: this.captureCurrentContextSnapshot(),
19820
19876
  server: {
@@ -19919,22 +19975,22 @@ class PraxisDynamicForm {
19919
19975
  const targetMode = nextMode || (plan.runtime?.clearMode ? 'create' : undefined);
19920
19976
  if (targetMode) {
19921
19977
  this.mode = targetMode;
19922
- if (plan.persistence?.saveBindings) {
19923
- const inputsKey = this.formInputsKey();
19924
- if (inputsKey) {
19925
- if (plan.runtime?.clearMode) {
19926
- this.asyncConfigStorage.clearConfig(inputsKey).subscribe();
19927
- }
19928
- else {
19929
- this.asyncConfigStorage
19930
- .loadConfig(inputsKey)
19931
- .pipe(take(1))
19932
- .subscribe((prev) => {
19933
- this.asyncConfigStorage
19934
- .saveConfig(inputsKey, { ...(prev || {}), mode: targetMode })
19935
- .subscribe();
19936
- });
19937
- }
19978
+ }
19979
+ if (plan.bindingsPatch?.presentationModeGlobal !== undefined) {
19980
+ this.presentationModeGlobal = plan.bindingsPatch.presentationModeGlobal;
19981
+ }
19982
+ else if (plan.runtime?.clearPresentationMode) {
19983
+ this.presentationModeGlobal = null;
19984
+ }
19985
+ if (plan.persistence?.saveBindings) {
19986
+ const inputsKey = this.formInputsKey();
19987
+ if (inputsKey) {
19988
+ // The editor document replaces the complete persisted binding snapshot.
19989
+ if (plan.bindingsPatch && Object.keys(plan.bindingsPatch).length) {
19990
+ this.asyncConfigStorage.saveConfig(inputsKey, plan.bindingsPatch).subscribe();
19991
+ }
19992
+ else {
19993
+ this.asyncConfigStorage.clearConfig(inputsKey).subscribe();
19938
19994
  }
19939
19995
  }
19940
19996
  }
@@ -20007,7 +20063,8 @@ class PraxisDynamicForm {
20007
20063
  this.persistFormConfig(key, this.config);
20008
20064
  }
20009
20065
  this.configChange.emit(this.config);
20010
- this.emitConfigPatchChange();
20066
+ this.presentation = contextSnapshot?.presentation ?? null;
20067
+ this.emitConfigPatchChange({ mode: this.mode, presentationModeGlobal: this.presentationModeGlobal, presentation: this.presentation });
20011
20068
  if (plan.runtime?.rebuildForm) {
20012
20069
  this.buildFormFromConfig({
20013
20070
  reason: 'editor-plan',
@@ -20046,10 +20103,11 @@ class PraxisDynamicForm {
20046
20103
  };
20047
20104
  return next;
20048
20105
  }
20049
- emitConfigPatchChange() {
20106
+ emitConfigPatchChange(bindings = {}) {
20050
20107
  this.configPatchChange.emit({
20051
20108
  inputPatch: {
20052
20109
  config: this.cloneFormConfigForPatch(this.config),
20110
+ ...bindings,
20053
20111
  },
20054
20112
  });
20055
20113
  }
@@ -20066,7 +20124,21 @@ class PraxisDynamicForm {
20066
20124
  if (!value)
20067
20125
  return null;
20068
20126
  const parsed = Number.parseFloat(value);
20069
- return Number.isFinite(parsed) ? parsed : null;
20127
+ if (!Number.isFinite(parsed))
20128
+ return null;
20129
+ const unit = value.trim().toLowerCase();
20130
+ // The authoring snapshot stores pixels. Preserve the host's root typography.
20131
+ if (unit.endsWith('rem')) {
20132
+ const rootSize = typeof document !== 'undefined'
20133
+ ? Number.parseFloat(getComputedStyle(document.documentElement).fontSize) : 16;
20134
+ return parsed * (Number.isFinite(rootSize) ? rootSize : 16);
20135
+ }
20136
+ if (unit.endsWith('em')) {
20137
+ const element = this.formHost?.nativeElement;
20138
+ const fontSize = element ? Number.parseFloat(getComputedStyle(element).fontSize) : 16;
20139
+ return parsed * (Number.isFinite(fontSize) ? fontSize : 16);
20140
+ }
20141
+ return /^[-+]?\d*\.?\d+(px)?$/.test(unit) ? parsed : null;
20070
20142
  }
20071
20143
  clearDynamicFormEditorPersistence(modes) {
20072
20144
  const inputsKey = this.formInputsKey();
@@ -20416,6 +20488,13 @@ class PraxisDynamicForm {
20416
20488
  }
20417
20489
  applyPresentationVars() {
20418
20490
  try {
20491
+ if (this.presentation !== undefined) {
20492
+ if (this.presentation)
20493
+ this.applyPresentationConfig(this.presentation);
20494
+ else
20495
+ this.resetPresentationVarsToDefaults();
20496
+ return;
20497
+ }
20419
20498
  const presFromConfig = this.config?.presentation;
20420
20499
  const key = this.formPresKey();
20421
20500
  if (key && presFromConfig) {
@@ -20435,7 +20514,7 @@ class PraxisDynamicForm {
20435
20514
  .loadConfig(key)
20436
20515
  .pipe(take(1))
20437
20516
  .subscribe((pres) => {
20438
- if (!pres)
20517
+ if (!pres || this.presentation !== undefined)
20439
20518
  return;
20440
20519
  this.applyPresentationConfig(pres);
20441
20520
  });
@@ -20486,7 +20565,7 @@ class PraxisDynamicForm {
20486
20565
  }
20487
20566
  }
20488
20567
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicForm, deps: [{ token: i1.GenericCrudService }, { token: i2.HttpClient }, { token: i1$3.FormBuilder }, { token: i0.ChangeDetectorRef }, { token: FormLayoutService }, { token: FormContextService }, { token: FormRulesService }, { token: i7.SettingsPanelService }, { token: i2$1.MatDialog }, { token: ASYNC_CONFIG_STORAGE }, { token: CONNECTION_STORAGE }, { token: i1.DynamicFormService }, { token: i9.MatSnackBar }, { token: CanvasStateService }, { token: DynamicFormLayoutService }, { token: ReactiveDeterminationRuntimeService }, { token: i1.ErrorMessageService }, { token: i1.SchemaNormalizerService }, { token: i1.ComponentMetadataRegistry }, { token: i1.GlobalConfigService }, { token: i1.ComponentKeyService }, { token: i1.LoadingOrchestrator }, { token: i0.NgZone }, { token: API_URL }, { token: PRAXIS_LOADING_RENDERER, optional: true }, { token: i13.Router, optional: true }, { token: i13.ActivatedRoute, optional: true }, { token: i1.FormHooksRegistry, optional: true }, { token: FORM_HOOKS_PRESETS, optional: true }, { token: i1.LoggerService, optional: true }, { token: i1.EnterpriseRuntimeContextService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
20489
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDynamicForm, isStandalone: true, selector: "praxis-dynamic-form", inputs: { resourcePath: "resourcePath", resourceId: "resourceId", initialValue: "initialValue", emptyState: "emptyState", editorialContext: "editorialContext", mode: "mode", config: "config", actions: "actions", schemaSource: "schemaSource", schemaUrl: "schemaUrl", readUrl: "readUrl", submitUrl: "submitUrl", submitMethod: "submitMethod", submitIdempotencyKey: "submitIdempotencyKey", submitCorrelationId: "submitCorrelationId", submitResourceVersion: "submitResourceVersion", submitResourceVersionTargetResourceKey: "submitResourceVersionTargetResourceKey", submitResourceVersionTargetIdField: "submitResourceVersionTargetIdField", responseSchemaUrl: "responseSchemaUrl", apiEndpointKey: "apiEndpointKey", apiUrlEntry: "apiUrlEntry", enableCustomization: "enableCustomization", showAiAssistant: "showAiAssistant", formId: "formId", componentInstanceId: "componentInstanceId", configPersistenceStrategy: "configPersistenceStrategy", layout: "layout", generatedLayoutPreset: "generatedLayoutPreset", layoutPolicy: "layoutPolicy", backConfig: "backConfig", hooks: "hooks", removeEmptyContainersOnSave: "removeEmptyContainersOnSave", reactiveValidation: "reactiveValidation", reactiveValidationDebounceMs: "reactiveValidationDebounceMs", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", readonlyModeGlobal: "readonlyModeGlobal", disabledModeGlobal: "disabledModeGlobal", presentationModeGlobal: "presentationModeGlobal", visibleGlobal: "visibleGlobal", fieldIconPolicy: "fieldIconPolicy", domainRules: "domainRules", customEndpoints: "customEndpoints" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formReset: "formReset", configChange: "configChange", configPatchChange: "configPatchChange", formReady: "formReady", valueChange: "valueChange", payloadPreviewChange: "payloadPreviewChange", syncCompleted: "syncCompleted", initializationError: "initializationError", loadingStateChange: "loadingStateChange", enableCustomizationChange: "enableCustomizationChange", customAction: "customAction", actionConfirmation: "actionConfirmation", schemaStatusChange: "schemaStatusChange", fieldRenderError: "fieldRenderError", ruleDiagnosticsChange: "ruleDiagnosticsChange", reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange" }, providers: [providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG)], viewQueries: [{ propertyName: "formHost", first: true, predicate: ["formHost"], descendants: true }, { propertyName: "fieldLoaders", predicate: DynamicFieldLoaderDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n <!-- Loading State -->\n <div class=\"form-loading\" role=\"status\" aria-live=\"polite\" aria-label=\"Carregando formul\u00E1rio\">\n <div class=\"form-loading-header\">\n <mat-progress-spinner diameter=\"32\" aria-label=\"Carregando formul\u00E1rio\"></mat-progress-spinner>\n <div class=\"form-loading-copy\">\n <p class=\"form-loading-title\">Carregando formul\u00E1rio...</p>\n <p class=\"form-loading-subtitle\">Preparando campos e op\u00E7\u00F5es do cadastro.</p>\n </div>\n </div>\n <div class=\"form-loading-skeleton\" aria-hidden=\"true\">\n <span class=\"form-loading-line form-loading-line-title\"></span>\n <span class=\"form-loading-line\"></span>\n <span class=\"form-loading-line form-loading-line-short\"></span>\n <span class=\"form-loading-field\"></span>\n <span class=\"form-loading-field form-loading-field-wide\"></span>\n </div>\n </div>\n} @else if (initializationStatus === 'error') {\n <!-- Error State -->\n <div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n </div>\n} @else if (initializationStatus === 'success') {\n <!-- Inline banner for schema change (only when customization is enabled) -->\n @if (shouldShowOutdatedInline()) {\n <div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n }\n\n <!-- Configuration Controls -->\n @if (shouldShowConfigControls && enableCustomization) {\n <div class=\"form-config-controls\">\n @if (showAiAssistant) {\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"dense\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('config-controls')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Abrir copiloto sem\u00E2ntico do formul\u00E1rio\">\n </button>\n }\n <button type=\"button\" praxisIconButton=\"settings\" size=\"dense\" (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [attr.aria-label]=\"configControlLabel\" [matTooltip]=\"configControlLabel\">\n </button>\n <button type=\"button\" praxisIconButton=\"link_off\" size=\"dense\" (click)=\"disconnect()\"\n [attr.aria-label]=\"disconnectControlLabel\" [matTooltip]=\"disconnectControlLabel\"\n [disabled]=\"isLoading\">\n </button>\n </div>\n }\n\n <!-- Form Content -->\n @if (!resourcePath && !hasExplicitSchemaUrl() && !hasRenderableConfig()) {\n <praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n }\n @if (shouldShowContextEmptyState()) {\n <div class=\"form-context-empty-state\" role=\"status\" aria-live=\"polite\">\n <praxis-empty-state-card\n [icon]=\"emptyState?.icon || 'touch_app'\"\n [title]=\"emptyState!.title\"\n [description]=\"emptyState?.description\"\n [tone]=\"emptyState?.tone || 'primary'\"\n [variant]=\"emptyState?.variant || 'transparent'\"\n [alignment]=\"emptyState?.alignment || 'center'\"\n [density]=\"emptyState?.density || 'compact'\"\n [iconContainer]=\"emptyState?.iconContainer || 'circle'\"\n [inline]=\"true\"\n />\n </div>\n } @else {\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n @if (enableCustomization && selectedElement) {\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n }\n\n @if (formBlocksBefore?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of (config.sections || []); track (section.id ?? $index); let sectionIndex = $index) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!isLastVisibleSection(section) ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n [class.title-only]=\"isSectionHeaderTitleOnly(section)\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getEffectiveSectionTitleGapBottom(section)\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\" (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\"\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n [praxisIconButton]=\"action.icon\"\n size=\"compact\"\n [busy]=\"action.loading\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" [praxisIconButton]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\" size=\"compact\"\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.role]=\"getSectionTitle(section) ? 'region' : null\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column, row)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n @for (renderItem of getColumnRenderItems(column); track renderItem.id) {\n @if (renderItem.kind === 'fields') {\n <ng-container dynamicFieldLoader [fields]=\"getRenderableFieldsForLoader(renderItem.fields)\" [formGroup]=\"form\"\n [enableExternalControlBinding]=\"true\"\n [readonlyMode]=\"effectiveReadonly\"\n [disabledMode]=\"effectiveDisabledMode\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (canvasFocus)=\"onFieldFocus($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n } @else {\n <praxis-rich-content\n class=\"form-layout-rich-content\"\n [ngClass]=\"renderItem.className || null\"\n [ngStyle]=\"renderItem.style || null\"\n [document]=\"renderItem.document\"\n [layout]=\"renderItem.layout\"\n [rootClassName]=\"renderItem.rootClassName || ''\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n }\n }\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (isLastVisibleSection(section) && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && isLastVisibleSection(section) && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"effectiveActions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner\n diameter=\"40\"\n color=\"primary\"\n [attr.aria-label]=\"config.messages?.loading?.submit || 'Salvando formul\u00E1rio'\"\n ></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n <praxis-rich-content\n [document]=\"formBlocksAfterDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n </form>\n }\n @if (showAiAssistant && !enableCustomization && mode === 'view' && !shouldShowContextEmptyState()) {\n <div class=\"ai-floating-assistant\">\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"compact\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('view-floating')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Pedir ajuda sobre este formul\u00E1rio\">\n </button>\n </div>\n }\n @if (showAiAssistant && 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]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"dynamic-form-ai-assistant\"\n panelTestId=\"dynamic-form-ai-assistant-panel\"\n submitTestId=\"dynamic-form-ai-assistant-submit\"\n applyTestId=\"dynamic-form-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", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@container praxis-form-row (min-width: 600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@container praxis-form-row (min-width: 900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@container praxis-form-row (min-width: 1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@container praxis-form-row (min-width: 1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative;--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--pdx-color-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent );--pfx-form-shell-padding: clamp(.9rem, 1.4vw, 1.2rem)}.form-config-controls{position:relative;top:auto;margin:0;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--pfx-form-shell-surface) 88%,var(--md-sys-color-surface) 12%);padding:8px var(--pfx-form-shell-padding);border:1px solid var(--pfx-form-footer-border);border-bottom-color:color-mix(in srgb,var(--pfx-form-footer-border) 72%,transparent);border-radius:var(--pfx-editorial-form-radius) var(--pfx-editorial-form-radius) 0 0;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:none;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.96;transition:opacity .16s ease,border-color .16s ease}.form-config-controls>*{pointer-events:auto}.form-config-controls:hover,.form-config-controls:focus-within{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%)}.form-config-controls .praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}.form-config-controls .praxis-icon-button:hover{color:var(--md-sys-color-primary)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant button{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:stretch;justify-content:center;padding:1.25rem;text-align:left;color:var(--md-sys-color-on-surface);gap:1rem;min-height:220px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 14%,var(--md-sys-color-outline-variant) 86%);border-radius:8px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 8%,transparent),transparent 42%),color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,var(--md-sys-color-surface) 22%);box-shadow:0 12px 28px #0f172a14}.form-loading-header{display:flex;align-items:center;gap:.85rem}.form-loading-copy{min-width:0}.form-loading p{margin:0}.form-loading-title{font-weight:700;color:var(--md-sys-color-on-surface)}.form-loading-subtitle{margin-top:.2rem;font-size:.875rem;color:var(--md-sys-color-on-surface-variant)}.form-loading-skeleton{display:grid;gap:.7rem}.form-loading-line,.form-loading-field{display:block;overflow:hidden;position:relative;border-radius:6px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 74%,var(--md-sys-color-primary) 6%)}.form-loading-line:after,.form-loading-field:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--md-sys-color-primary) 16%,white 18%),transparent);animation:form-loading-shimmer 1.4s ease-in-out infinite}.form-loading-line{height:12px}.form-loading-line-title{width:min(42%,240px)}.form-loading-line-short{width:min(64%,360px)}.form-loading-field{height:44px}.form-loading-field-wide{height:72px}@keyframes form-loading-shimmer{to{transform:translate(100%)}}@media(prefers-reduced-motion:reduce){.form-loading-line:after,.form-loading-field:after{animation:none;transform:none;opacity:.28}}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;max-width:100%;min-width:0;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --pdx-color-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --pdx-color-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var( --pdx-color-primary, var(--md-sys-color-primary) );--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pdx-presentation-label-size: var(--pfx-pres-compact-label-size, .78rem);--pdx-presentation-value-size: var(--pfx-pres-compact-value-size, 1rem);--pdx-presentation-icon-size: var(--pfx-pres-icon-size, 18px);--pdx-presentation-row-gap: var(--pfx-pres-row-gap, .5rem);--pdx-presentation-column-gap: var(--pfx-pres-column-gap, .5rem);--pdx-presentation-section-gap: var(--pfx-pres-section-gap, .75rem);--pdx-presentation-label-width: var(--pfx-pres-label-width, 220px);--pdx-presentation-flag-height: var(--pfx-pres-boolean-min-height, 22px);--pdx-presentation-flag-radius: var(--pfx-pres-boolean-radius, 999px);--pdx-presentation-flag-padding: var(--pfx-pres-boolean-padding, 0 8px);--pdx-presentation-flag-active-color: var( --pfx-pres-boolean-active-color, var(--md-sys-color-primary) );--pdx-presentation-flag-active-bg: var( --pfx-pres-boolean-active-bg, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent) );--pdx-presentation-flag-inactive-color: var( --pfx-pres-boolean-inactive-color, var(--md-sys-color-on-surface-variant) );--pdx-presentation-flag-inactive-bg: var( --pfx-pres-boolean-inactive-bg, color-mix(in srgb, var(--md-sys-color-outline-variant) 34%, transparent) );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.canvas-mode-enabled{border:1px solid var(--pfx-form-footer-border);border-radius:var(--pfx-editorial-form-radius);background:linear-gradient(180deg,color-mix(in srgb,var(--pfx-form-shell-surface) 86%,transparent),color-mix(in srgb,var(--pfx-editorial-form-surface-muted) 42%,transparent));overflow:visible}.form-config-controls+.praxis-dynamic-form.canvas-mode-enabled{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks{margin-inline:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper:first-of-type,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks:first-child{margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>praxis-form-actions[data-actions-placement=afterSections]{display:block;margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.editorial-visual-context{--_pfx-editorial-host-text: var( --editorial-text-primary, var(--foreground, var(--mat-sys-on-surface, #1d1b20)) );--_pfx-editorial-host-text-muted: var( --editorial-text-secondary, var( --muted-foreground, color-mix(in srgb, var(--_pfx-editorial-host-text) 64%, transparent) ) );--_pfx-editorial-host-surface: var( --editorial-surface-primary, var(--card, var(--mat-sys-surface-container, #ffffff)) );--_pfx-editorial-host-surface-muted: var( --editorial-surface-secondary, var(--surface-dim, var(--muted, var(--mat-sys-surface-container-low, #f7f2fa))) );--_pfx-editorial-host-border: var( --editorial-border-color, var(--border, var(--mat-sys-outline-variant, #cac4d0)) );--_pfx-editorial-host-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--primary, var(--mat-sys-primary, #6750a4))) );--_pfx-editorial-host-accent-text: var( --editorial-cta-primary-text, var( --editorial-accent-contrast, var(--primary-foreground, var(--mat-sys-on-primary, #ffffff)) ) );--_pfx-editorial-host-accent-container: var( --primary-container, color-mix(in srgb, var(--_pfx-editorial-host-accent) 16%, var(--_pfx-editorial-host-surface) 84%) );--_pfx-editorial-host-accent-container-text: var( --primary-container-fg, var(--_pfx-editorial-host-accent) );font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--_pfx-editorial-host-text);--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--_pfx-editorial-host-surface)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--_pfx-editorial-host-surface-muted) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--_pfx-editorial-host-border)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--_pfx-editorial-host-text) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, color-mix( in srgb, var(--_pfx-editorial-host-text-muted) 86%, var(--_pfx-editorial-host-text) 14% ) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--_pfx-editorial-host-accent)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--_pfx-editorial-host-accent-text)) );--pfx-editorial-form-accent-container: var(--_pfx-editorial-host-accent-container);--pfx-editorial-form-accent-container-text: var(--_pfx-editorial-host-accent-container-text);--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --editorial-text-primary, inherit );--md-sys-color-on-surface-variant: var( --editorial-text-secondary, inherit );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-primary-container: var( --pfx-editorial-form-accent-container, var(--md-sys-color-primary-container) );--md-sys-color-on-primary-container: var( --pfx-editorial-form-accent-container-text, var(--md-sys-color-on-primary-container) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );--mat-sys-on-surface: var( --editorial-text-primary, inherit );--mat-sys-on-surface-variant: var( --editorial-text-secondary, inherit );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );color:inherit;color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:var(--pdx-presentation-column-gap);margin-bottom:var(--pdx-presentation-row-gap)}.praxis-dynamic-form.presentation-mode{--pfx-pres-on-surface: var( --pdx-color-text-primary, var(--pfx-editorial-form-text, var(--pfx-form-label-strong, currentColor)) );--pfx-pres-on-surface-variant: var( --pdx-color-text-secondary, var( --pfx-editorial-form-text-muted, var( --pfx-form-label-muted, color-mix(in srgb, var(--pfx-pres-on-surface) 78%, transparent) ) ) )}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:var(--pdx-presentation-section-gap) .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:var(--pdx-presentation-column-gap, .35rem);margin-bottom:var(--pdx-presentation-row-gap, .35rem)}.praxis-dynamic-form.pres-compact .form-section{padding:var(--pdx-presentation-section-gap, .5rem) .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:minmax(0,var(--pfx-presentation-label-w, var(--pdx-presentation-label-width))) minmax(0,1fr);align-items:baseline;column-gap:var(--pdx-presentation-column-gap, 10px)}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}@media(max-width:480px){.praxis-dynamic-form.pres-label-left .praxis-presentation{grid-template-columns:minmax(0,1fr);row-gap:4px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:start}}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);max-width:100%;min-width:0;background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section{border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;color:var(--pfx-editorial-form-text);box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{position:relative;display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 18px)}.section-heading:after{content:\"\";position:absolute;right:0;bottom:0;left:0;height:2px;pointer-events:none;background:linear-gradient(90deg,transparent 0%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 8%,var(--pfx-form-section-divider) 46%,var(--pfx-form-section-divider) 54%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 92%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%);mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 10px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:none}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn.tone-primary{color:var(--md-sys-color-primary)}.section-heading-action-btn.tone-accent,.section-heading-action-btn.tone-secondary{color:var(--md-sys-color-tertiary)}.section-heading-action-btn.tone-warn,.section-heading-action-btn.tone-danger,.section-heading-action-btn.tone-error{color:var(--md-sys-color-error)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 16px)}.form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 16px)}:host(.pfx-form-section-divider-inline-title) .form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form:not(.canvas-mode-enabled)>praxis-form-actions[data-actions-placement=afterSections]{margin-top:18px}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);max-width:100%;min-width:0;transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=entityLookup],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;grid-template-columns:minmax(0,1fr);align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;max-width:100%;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-layout-rich-content{display:block;width:100%;max-width:100%;min-width:0;margin-bottom:var(--pfx-field-gap, 10px);color:var(--pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant));font:var(--mdc-typography-body-medium, 400 14px/20px system-ui);overflow-wrap:anywhere}:host ::ng-deep .form-layout-rich-content .prx-rich-content-root{display:grid;gap:8px;min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-node{min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-text{color:inherit;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{border:1px solid color-mix(in srgb,var(--pfx-editorial-form-accent) 12%,var(--pfx-editorial-form-border) 88%);border-left:3px solid var(--pfx-editorial-form-accent);border-radius:8px;background:color-mix(in srgb,var(--pfx-editorial-form-accent-container) 12%,var(--pfx-editorial-form-surface-muted) 88%)}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:flex-start;padding:11px 12px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note:before{content:\"info\";display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;color:var(--pfx-editorial-form-accent);font-family:Material Symbols Outlined;font-size:20px;font-weight:400;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{padding:10px 12px;color:var(--pfx-editorial-form-text)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-compose{align-items:flex-start;gap:10px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-icon{color:var(--pfx-editorial-form-accent);font-size:20px;line-height:20px;margin-top:1px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider{display:grid;grid-template-columns:minmax(24px,1fr) auto minmax(24px,1fr);align-items:center;gap:10px;color:var(--pfx-editorial-form-text-muted);font:var(--mdc-typography-label-small, 600 12px/16px system-ui);text-transform:uppercase}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:before,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:after{content:\"\";height:1px;background:var(--pfx-editorial-form-border)}:host ::ng-deep .form-layout-rich-content .prx-rich-card{gap:6px;padding:12px 14px;border-color:var(--pfx-editorial-form-border);border-radius:8px;background:var(--pfx-editorial-form-surface-muted);color:var(--pfx-editorial-form-text);box-shadow:none}:host ::ng-deep .form-layout-rich-content .prx-rich-card-title{color:var(--pfx-editorial-form-text);font:var(--mdc-typography-title-small, 600 14px/20px system-ui)}:host ::ng-deep .form-layout-rich-content .prx-rich-card-subtitle,:host ::ng-deep .form-layout-rich-content .prx-rich-metric-caption{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-card .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-badge{background:var(--pfx-editorial-form-accent-container);color:var(--pfx-editorial-form-accent-container-text)}.form-row.grid-12{container-type:inline-size;container-name:praxis-form-row;display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.column-drop-wrapper,.row-drop-wrapper,.form-layout-rich-content,.praxis-dynamic-form .mat-mdc-form-field,.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{max-width:100%;min-width:0}:host ::ng-deep .praxis-dynamic-form .pfx-field-shell,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-wrapper,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-host,:host ::ng-deep .praxis-dynamic-form .mat-mdc-form-field,:host ::ng-deep .praxis-dynamic-form .mat-mdc-text-field-wrapper,:host ::ng-deep .praxis-dynamic-form .mdc-text-field{width:100%;max-width:100%;min-width:0}.form-section{padding:clamp(.75rem,4vw,1rem)}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 14px)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}}.section-title{display:flex;align-items:center;gap:8px}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:100%;min-width:0}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{content:\"\";display:block;flex:1 1 auto;min-width:var(--pfx-form-section-title-inline-divider-min-width, 48px);height:2px;margin-left:var(--pfx-form-section-title-inline-divider-gap, 12px);pointer-events:none;background:linear-gradient(90deg,var(--pfx-form-section-divider) 0%,var(--pfx-form-section-divider) 62%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 88%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%);mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%)}:host(.pfx-form-section-divider-inline-title) .section-heading.align-center .section-title:after{display:none}@media(max-width:640px){:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:block}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:auto}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{display:none}}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.form-context-empty-state{display:grid;min-height:var(--pdx-form-context-empty-min-height, clamp(9.25rem, 20vh, 14rem));place-items:center;padding:var(--pdx-form-context-empty-padding, clamp(1.5rem, 3vw, 2.5rem))}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick", "canvasFocus"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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: i3.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i17.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i19.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: CanvasToolbarComponent, selector: "praxis-canvas-toolbar", inputs: ["selectedElement"], outputs: ["editMetadata", "delete", "moveUp", "moveDown", "selectPath", "requestClose", "toggleReadonly", "toggleRequired", "toggleHidden", "toggleDisabled"] }, { kind: "component", type: PraxisFormActionsComponent, selector: "praxis-form-actions", inputs: ["actions", "editorialVisualContext", "isSubmitting", "formIsValid", "submitError", "invalidRequiredFieldLabels", "suppressInvalidSubmitHint", "formId", "actionOverrides"], outputs: ["action"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone", "variant", "alignment", "density", "iconContainer"] }, { 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: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"] }] });
20568
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDynamicForm, isStandalone: true, selector: "praxis-dynamic-form", inputs: { resourcePath: "resourcePath", resourceId: "resourceId", initialValue: "initialValue", emptyState: "emptyState", editorialContext: "editorialContext", mode: "mode", config: "config", actions: "actions", schemaSource: "schemaSource", schemaUrl: "schemaUrl", readUrl: "readUrl", submitUrl: "submitUrl", submitMethod: "submitMethod", submitIdempotencyKey: "submitIdempotencyKey", submitCorrelationId: "submitCorrelationId", submitResourceVersion: "submitResourceVersion", submitResourceVersionTargetResourceKey: "submitResourceVersionTargetResourceKey", submitResourceVersionTargetIdField: "submitResourceVersionTargetIdField", responseSchemaUrl: "responseSchemaUrl", apiEndpointKey: "apiEndpointKey", apiUrlEntry: "apiUrlEntry", enableCustomization: "enableCustomization", showAiAssistant: "showAiAssistant", formId: "formId", componentInstanceId: "componentInstanceId", configPersistenceStrategy: "configPersistenceStrategy", layout: "layout", generatedLayoutPreset: "generatedLayoutPreset", layoutPolicy: "layoutPolicy", backConfig: "backConfig", hooks: "hooks", removeEmptyContainersOnSave: "removeEmptyContainersOnSave", reactiveValidation: "reactiveValidation", reactiveValidationDebounceMs: "reactiveValidationDebounceMs", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", readonlyModeGlobal: "readonlyModeGlobal", disabledModeGlobal: "disabledModeGlobal", presentationModeGlobal: "presentationModeGlobal", presentation: "presentation", visibleGlobal: "visibleGlobal", fieldIconPolicy: "fieldIconPolicy", domainRules: "domainRules", customEndpoints: "customEndpoints" }, outputs: { formSubmit: "formSubmit", formCancel: "formCancel", formReset: "formReset", configChange: "configChange", configPatchChange: "configPatchChange", formReady: "formReady", valueChange: "valueChange", payloadPreviewChange: "payloadPreviewChange", syncCompleted: "syncCompleted", initializationError: "initializationError", loadingStateChange: "loadingStateChange", enableCustomizationChange: "enableCustomizationChange", customAction: "customAction", actionConfirmation: "actionConfirmation", schemaStatusChange: "schemaStatusChange", fieldRenderError: "fieldRenderError", ruleDiagnosticsChange: "ruleDiagnosticsChange", reactiveDeterminationExecuted: "reactiveDeterminationExecuted", reactiveDeterminationPendingChange: "reactiveDeterminationPendingChange" }, providers: [providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG)], viewQueries: [{ propertyName: "formHost", first: true, predicate: ["formHost"], descendants: true }, { propertyName: "fieldLoaders", predicate: DynamicFieldLoaderDirective, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n <!-- Loading State -->\n <div class=\"form-loading\" role=\"status\" aria-live=\"polite\" aria-label=\"Carregando formul\u00E1rio\">\n <div class=\"form-loading-header\">\n <mat-progress-spinner diameter=\"32\" aria-label=\"Carregando formul\u00E1rio\"></mat-progress-spinner>\n <div class=\"form-loading-copy\">\n <p class=\"form-loading-title\">Carregando formul\u00E1rio...</p>\n <p class=\"form-loading-subtitle\">Preparando campos e op\u00E7\u00F5es do cadastro.</p>\n </div>\n </div>\n <div class=\"form-loading-skeleton\" aria-hidden=\"true\">\n <span class=\"form-loading-line form-loading-line-title\"></span>\n <span class=\"form-loading-line\"></span>\n <span class=\"form-loading-line form-loading-line-short\"></span>\n <span class=\"form-loading-field\"></span>\n <span class=\"form-loading-field form-loading-field-wide\"></span>\n </div>\n </div>\n} @else if (initializationStatus === 'error') {\n <!-- Error State -->\n <div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n </div>\n} @else if (initializationStatus === 'success') {\n <!-- Inline banner for schema change (only when customization is enabled) -->\n @if (shouldShowOutdatedInline()) {\n <div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n }\n\n <!-- Configuration Controls -->\n @if (shouldShowConfigControls && enableCustomization) {\n <div class=\"form-config-controls\">\n @if (showAiAssistant) {\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"dense\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('config-controls')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Abrir copiloto sem\u00E2ntico do formul\u00E1rio\">\n </button>\n }\n <button type=\"button\" praxisIconButton=\"settings\" size=\"dense\" (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [attr.aria-label]=\"configControlLabel\" [matTooltip]=\"configControlLabel\">\n </button>\n <button type=\"button\" praxisIconButton=\"link_off\" size=\"dense\" (click)=\"disconnect()\"\n [attr.aria-label]=\"disconnectControlLabel\" [matTooltip]=\"disconnectControlLabel\"\n [disabled]=\"isLoading\">\n </button>\n </div>\n }\n\n <!-- Form Content -->\n @if (!resourcePath && !hasExplicitSchemaUrl() && !hasRenderableConfig()) {\n <praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n }\n @if (shouldShowContextEmptyState()) {\n <div class=\"form-context-empty-state\" role=\"status\" aria-live=\"polite\">\n <praxis-empty-state-card\n [icon]=\"emptyState?.icon || 'touch_app'\"\n [title]=\"emptyState!.title\"\n [description]=\"emptyState?.description\"\n [tone]=\"emptyState?.tone || 'primary'\"\n [variant]=\"emptyState?.variant || 'transparent'\"\n [alignment]=\"emptyState?.alignment || 'center'\"\n [density]=\"emptyState?.density || 'compact'\"\n [iconContainer]=\"emptyState?.iconContainer || 'circle'\"\n [inline]=\"true\"\n />\n </div>\n } @else {\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n @if (enableCustomization && selectedElement) {\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n }\n\n @if (formBlocksBefore?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of (config.sections || []); track (section.id ?? $index); let sectionIndex = $index) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!isLastVisibleSection(section) ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n [class.title-only]=\"isSectionHeaderTitleOnly(section)\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getEffectiveSectionTitleGapBottom(section)\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\" (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\"\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n [praxisIconButton]=\"action.icon\"\n size=\"compact\"\n [busy]=\"action.loading\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" [praxisIconButton]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\" size=\"compact\"\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.role]=\"getSectionTitle(section) ? 'region' : null\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column, row)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n @for (renderItem of getColumnRenderItems(column); track renderItem.id) {\n @if (renderItem.kind === 'fields') {\n <ng-container dynamicFieldLoader [fields]=\"getRenderableFieldsForLoader(renderItem.fields)\" [formGroup]=\"form\"\n [enableExternalControlBinding]=\"true\"\n [readonlyMode]=\"effectiveReadonly\"\n [disabledMode]=\"effectiveDisabledMode\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (canvasFocus)=\"onFieldFocus($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n } @else {\n <praxis-rich-content\n class=\"form-layout-rich-content\"\n [ngClass]=\"renderItem.className || null\"\n [ngStyle]=\"renderItem.style || null\"\n [document]=\"renderItem.document\"\n [layout]=\"renderItem.layout\"\n [rootClassName]=\"renderItem.rootClassName || ''\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n }\n }\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (isLastVisibleSection(section) && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && isLastVisibleSection(section) && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"effectiveActions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner\n diameter=\"40\"\n color=\"primary\"\n [attr.aria-label]=\"config.messages?.loading?.submit || 'Salvando formul\u00E1rio'\"\n ></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n <praxis-rich-content\n [document]=\"formBlocksAfterDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n </form>\n }\n @if (showAiAssistant && !enableCustomization && mode === 'view' && !shouldShowContextEmptyState()) {\n <div class=\"ai-floating-assistant\">\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"compact\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('view-floating')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Pedir ajuda sobre este formul\u00E1rio\">\n </button>\n </div>\n }\n @if (showAiAssistant && 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]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"dynamic-form-ai-assistant\"\n panelTestId=\"dynamic-form-ai-assistant-panel\"\n submitTestId=\"dynamic-form-ai-assistant-submit\"\n applyTestId=\"dynamic-form-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", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@container praxis-form-row (min-width: 600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@container praxis-form-row (min-width: 900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@container praxis-form-row (min-width: 1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@container praxis-form-row (min-width: 1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative;--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--pdx-color-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent );--pfx-form-shell-padding: clamp(.9rem, 1.4vw, 1.2rem)}.form-config-controls{position:relative;top:auto;margin:0;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--pfx-form-shell-surface) 88%,var(--md-sys-color-surface) 12%);padding:8px var(--pfx-form-shell-padding);border:1px solid var(--pfx-form-footer-border);border-bottom-color:color-mix(in srgb,var(--pfx-form-footer-border) 72%,transparent);border-radius:var(--pfx-editorial-form-radius) var(--pfx-editorial-form-radius) 0 0;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:none;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.96;transition:opacity .16s ease,border-color .16s ease}.form-config-controls>*{pointer-events:auto}.form-config-controls:hover,.form-config-controls:focus-within{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%)}.form-config-controls .praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}.form-config-controls .praxis-icon-button:hover{color:var(--md-sys-color-primary)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant button{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:stretch;justify-content:center;padding:1.25rem;text-align:left;color:var(--md-sys-color-on-surface);gap:1rem;min-height:220px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 14%,var(--md-sys-color-outline-variant) 86%);border-radius:8px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 8%,transparent),transparent 42%),color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,var(--md-sys-color-surface) 22%);box-shadow:0 12px 28px #0f172a14}.form-loading-header{display:flex;align-items:center;gap:.85rem}.form-loading-copy{min-width:0}.form-loading p{margin:0}.form-loading-title{font-weight:700;color:var(--md-sys-color-on-surface)}.form-loading-subtitle{margin-top:.2rem;font-size:.875rem;color:var(--md-sys-color-on-surface-variant)}.form-loading-skeleton{display:grid;gap:.7rem}.form-loading-line,.form-loading-field{display:block;overflow:hidden;position:relative;border-radius:6px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 74%,var(--md-sys-color-primary) 6%)}.form-loading-line:after,.form-loading-field:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--md-sys-color-primary) 16%,white 18%),transparent);animation:form-loading-shimmer 1.4s ease-in-out infinite}.form-loading-line{height:12px}.form-loading-line-title{width:min(42%,240px)}.form-loading-line-short{width:min(64%,360px)}.form-loading-field{height:44px}.form-loading-field-wide{height:72px}@keyframes form-loading-shimmer{to{transform:translate(100%)}}@media(prefers-reduced-motion:reduce){.form-loading-line:after,.form-loading-field:after{animation:none;transform:none;opacity:.28}}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;max-width:100%;min-width:0;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --pdx-color-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --pdx-color-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var( --pdx-color-primary, var(--md-sys-color-primary) );--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pdx-presentation-label-size: var(--pfx-pres-compact-label-size, .78rem);--pdx-presentation-value-size: var(--pfx-pres-compact-value-size, 1rem);--pdx-presentation-icon-size: var(--pfx-pres-icon-size, 18px);--pdx-presentation-row-gap: var(--pfx-pres-row-gap, .5rem);--pdx-presentation-column-gap: var(--pfx-pres-column-gap, .5rem);--pdx-presentation-section-gap: var(--pfx-pres-section-gap, .75rem);--pdx-presentation-label-width: var(--pfx-pres-label-width, 220px);--pdx-presentation-flag-height: var(--pfx-pres-boolean-min-height, 22px);--pdx-presentation-flag-radius: var(--pfx-pres-boolean-radius, 999px);--pdx-presentation-flag-padding: var(--pfx-pres-boolean-padding, 0 8px);--pdx-presentation-flag-active-color: var( --pfx-pres-boolean-active-color, var(--md-sys-color-primary) );--pdx-presentation-flag-active-bg: var( --pfx-pres-boolean-active-bg, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent) );--pdx-presentation-flag-inactive-color: var( --pfx-pres-boolean-inactive-color, var(--md-sys-color-on-surface-variant) );--pdx-presentation-flag-inactive-bg: var( --pfx-pres-boolean-inactive-bg, color-mix(in srgb, var(--md-sys-color-outline-variant) 34%, transparent) );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.canvas-mode-enabled{border:1px solid var(--pfx-form-footer-border);border-radius:var(--pfx-editorial-form-radius);background:linear-gradient(180deg,color-mix(in srgb,var(--pfx-form-shell-surface) 86%,transparent),color-mix(in srgb,var(--pfx-editorial-form-surface-muted) 42%,transparent));overflow:visible}.form-config-controls+.praxis-dynamic-form.canvas-mode-enabled{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks{margin-inline:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper:first-of-type,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks:first-child{margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>praxis-form-actions[data-actions-placement=afterSections]{display:block;margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.editorial-visual-context{--_pfx-editorial-host-text: var( --editorial-text-primary, var(--foreground, var(--mat-sys-on-surface, #1d1b20)) );--_pfx-editorial-host-text-muted: var( --editorial-text-secondary, var( --muted-foreground, color-mix(in srgb, var(--_pfx-editorial-host-text) 64%, transparent) ) );--_pfx-editorial-host-surface: var( --editorial-surface-primary, var(--card, var(--mat-sys-surface-container, #ffffff)) );--_pfx-editorial-host-surface-muted: var( --editorial-surface-secondary, var(--surface-dim, var(--muted, var(--mat-sys-surface-container-low, #f7f2fa))) );--_pfx-editorial-host-border: var( --editorial-border-color, var(--border, var(--mat-sys-outline-variant, #cac4d0)) );--_pfx-editorial-host-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--primary, var(--mat-sys-primary, #6750a4))) );--_pfx-editorial-host-accent-text: var( --editorial-cta-primary-text, var( --editorial-accent-contrast, var(--primary-foreground, var(--mat-sys-on-primary, #ffffff)) ) );--_pfx-editorial-host-accent-container: var( --primary-container, color-mix(in srgb, var(--_pfx-editorial-host-accent) 16%, var(--_pfx-editorial-host-surface) 84%) );--_pfx-editorial-host-accent-container-text: var( --primary-container-fg, var(--_pfx-editorial-host-accent) );font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--_pfx-editorial-host-text);--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--_pfx-editorial-host-surface)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--_pfx-editorial-host-surface-muted) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--_pfx-editorial-host-border)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--_pfx-editorial-host-text) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, color-mix( in srgb, var(--_pfx-editorial-host-text-muted) 86%, var(--_pfx-editorial-host-text) 14% ) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--_pfx-editorial-host-accent)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--_pfx-editorial-host-accent-text)) );--pfx-editorial-form-accent-container: var(--_pfx-editorial-host-accent-container);--pfx-editorial-form-accent-container-text: var(--_pfx-editorial-host-accent-container-text);--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --editorial-text-primary, inherit );--md-sys-color-on-surface-variant: var( --editorial-text-secondary, inherit );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-primary-container: var( --pfx-editorial-form-accent-container, var(--md-sys-color-primary-container) );--md-sys-color-on-primary-container: var( --pfx-editorial-form-accent-container-text, var(--md-sys-color-on-primary-container) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );--mat-sys-on-surface: var( --editorial-text-primary, inherit );--mat-sys-on-surface-variant: var( --editorial-text-secondary, inherit );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );color:inherit;color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:var(--pdx-presentation-column-gap);margin-bottom:var(--pdx-presentation-row-gap)}.praxis-dynamic-form.presentation-mode{--pfx-pres-on-surface: var( --pdx-color-text-primary, var(--pfx-editorial-form-text, var(--pfx-form-label-strong, currentColor)) );--pfx-pres-on-surface-variant: var( --pdx-color-text-secondary, var( --pfx-editorial-form-text-muted, var( --pfx-form-label-muted, color-mix(in srgb, var(--pfx-pres-on-surface) 78%, transparent) ) ) )}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:var(--pdx-presentation-section-gap) .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:var(--pdx-presentation-column-gap, .35rem);margin-bottom:var(--pdx-presentation-row-gap, .35rem)}.praxis-dynamic-form.pres-compact .form-section{padding:var(--pdx-presentation-section-gap, .5rem) .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:minmax(0,var(--pfx-presentation-label-w, var(--pdx-presentation-label-width))) minmax(0,1fr);align-items:baseline;column-gap:var(--pdx-presentation-column-gap, 10px)}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}@media(max-width:480px){.praxis-dynamic-form.pres-label-left .praxis-presentation{grid-template-columns:minmax(0,1fr);row-gap:4px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:start}}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);max-width:100%;min-width:0;background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section:not(.section-appearance-plain){border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;color:var(--pfx-editorial-form-text);box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{position:relative;display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 18px)}.section-heading:after{content:\"\";position:absolute;right:0;bottom:0;left:0;height:2px;pointer-events:none;background:linear-gradient(90deg,transparent 0%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 8%,var(--pfx-form-section-divider) 46%,var(--pfx-form-section-divider) 54%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 92%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%);mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 10px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:none}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn.tone-primary{color:var(--md-sys-color-primary)}.section-heading-action-btn.tone-accent,.section-heading-action-btn.tone-secondary{color:var(--md-sys-color-tertiary)}.section-heading-action-btn.tone-warn,.section-heading-action-btn.tone-danger,.section-heading-action-btn.tone-error{color:var(--md-sys-color-error)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.praxis-dynamic-form .form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 16px)}.form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 16px)}:host(.pfx-form-section-divider-inline-title) .form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form:not(.canvas-mode-enabled)>praxis-form-actions[data-actions-placement=afterSections]{margin-top:18px}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);max-width:100%;min-width:0;transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=entityLookup],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;grid-template-columns:minmax(0,1fr);align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;max-width:100%;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-layout-rich-content{display:block;width:100%;max-width:100%;min-width:0;margin-bottom:var(--pfx-field-gap, 10px);color:var(--pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant));font:var(--mdc-typography-body-medium, 400 14px/20px system-ui);overflow-wrap:anywhere}:host ::ng-deep .form-layout-rich-content .prx-rich-content-root{display:grid;gap:8px;min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-node{min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-text{color:inherit;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{border:1px solid color-mix(in srgb,var(--pfx-editorial-form-accent) 12%,var(--pfx-editorial-form-border) 88%);border-left:3px solid var(--pfx-editorial-form-accent);border-radius:8px;background:color-mix(in srgb,var(--pfx-editorial-form-accent-container) 12%,var(--pfx-editorial-form-surface-muted) 88%)}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:flex-start;padding:11px 12px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note:before{content:\"info\";display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;color:var(--pfx-editorial-form-accent);font-family:Material Symbols Outlined;font-size:20px;font-weight:400;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{padding:10px 12px;color:var(--pfx-editorial-form-text)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-compose{align-items:flex-start;gap:10px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-icon{color:var(--pfx-editorial-form-accent);font-size:20px;line-height:20px;margin-top:1px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider{display:grid;grid-template-columns:minmax(24px,1fr) auto minmax(24px,1fr);align-items:center;gap:10px;color:var(--pfx-editorial-form-text-muted);font:var(--mdc-typography-label-small, 600 12px/16px system-ui);text-transform:uppercase}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:before,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:after{content:\"\";height:1px;background:var(--pfx-editorial-form-border)}:host ::ng-deep .form-layout-rich-content .prx-rich-card{gap:6px;padding:12px 14px;border-color:var(--pfx-editorial-form-border);border-radius:8px;background:var(--pfx-editorial-form-surface-muted);color:var(--pfx-editorial-form-text);box-shadow:none}:host ::ng-deep .form-layout-rich-content .prx-rich-card-title{color:var(--pfx-editorial-form-text);font:var(--mdc-typography-title-small, 600 14px/20px system-ui)}:host ::ng-deep .form-layout-rich-content .prx-rich-card-subtitle,:host ::ng-deep .form-layout-rich-content .prx-rich-metric-caption{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-card .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-badge{background:var(--pfx-editorial-form-accent-container);color:var(--pfx-editorial-form-accent-container-text)}.form-row.grid-12{container-type:inline-size;container-name:praxis-form-row;display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.column-drop-wrapper,.row-drop-wrapper,.form-layout-rich-content,.praxis-dynamic-form .mat-mdc-form-field,.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{max-width:100%;min-width:0}:host ::ng-deep .praxis-dynamic-form .pfx-field-shell,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-wrapper,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-host,:host ::ng-deep .praxis-dynamic-form .mat-mdc-form-field,:host ::ng-deep .praxis-dynamic-form .mat-mdc-text-field-wrapper,:host ::ng-deep .praxis-dynamic-form .mdc-text-field{width:100%;max-width:100%;min-width:0}.form-section{padding:clamp(.75rem,4vw,1rem)}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 14px)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}}.section-title{display:flex;align-items:center;gap:8px}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:100%;min-width:0}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{content:\"\";display:block;flex:1 1 auto;min-width:var(--pfx-form-section-title-inline-divider-min-width, 48px);height:2px;margin-left:var(--pfx-form-section-title-inline-divider-gap, 12px);pointer-events:none;background:linear-gradient(90deg,var(--pfx-form-section-divider) 0%,var(--pfx-form-section-divider) 62%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 88%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%);mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%)}:host(.pfx-form-section-divider-inline-title) .section-heading.align-center .section-title:after{display:none}@media(max-width:640px){:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:block}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:auto}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{display:none}}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.form-context-empty-state{display:grid;min-height:var(--pdx-form-context-empty-min-height, clamp(9.25rem, 20vh, 14rem));place-items:center;padding:var(--pdx-form-context-empty-padding, clamp(1.5rem, 3vw, 2.5rem))}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick", "canvasFocus"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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: i3.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i17.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i19.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: CanvasToolbarComponent, selector: "praxis-canvas-toolbar", inputs: ["selectedElement"], outputs: ["editMetadata", "delete", "moveUp", "moveDown", "selectPath", "requestClose", "toggleReadonly", "toggleRequired", "toggleHidden", "toggleDisabled"] }, { kind: "component", type: PraxisFormActionsComponent, selector: "praxis-form-actions", inputs: ["actions", "editorialVisualContext", "isSubmitting", "formIsValid", "submitError", "invalidRequiredFieldLabels", "suppressInvalidSubmitHint", "formId", "actionOverrides"], outputs: ["action"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone", "variant", "alignment", "density", "iconContainer"] }, { 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: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "layout", "rootClassName"] }] });
20490
20569
  }
20491
20570
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicForm, decorators: [{
20492
20571
  type: Component,
@@ -20508,7 +20587,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20508
20587
  EmptyStateCardComponent,
20509
20588
  PraxisAiAssistantShellComponent,
20510
20589
  PraxisRichContent,
20511
- ], template: "@if (isLoading) {\n <!-- Loading State -->\n <div class=\"form-loading\" role=\"status\" aria-live=\"polite\" aria-label=\"Carregando formul\u00E1rio\">\n <div class=\"form-loading-header\">\n <mat-progress-spinner diameter=\"32\" aria-label=\"Carregando formul\u00E1rio\"></mat-progress-spinner>\n <div class=\"form-loading-copy\">\n <p class=\"form-loading-title\">Carregando formul\u00E1rio...</p>\n <p class=\"form-loading-subtitle\">Preparando campos e op\u00E7\u00F5es do cadastro.</p>\n </div>\n </div>\n <div class=\"form-loading-skeleton\" aria-hidden=\"true\">\n <span class=\"form-loading-line form-loading-line-title\"></span>\n <span class=\"form-loading-line\"></span>\n <span class=\"form-loading-line form-loading-line-short\"></span>\n <span class=\"form-loading-field\"></span>\n <span class=\"form-loading-field form-loading-field-wide\"></span>\n </div>\n </div>\n} @else if (initializationStatus === 'error') {\n <!-- Error State -->\n <div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n </div>\n} @else if (initializationStatus === 'success') {\n <!-- Inline banner for schema change (only when customization is enabled) -->\n @if (shouldShowOutdatedInline()) {\n <div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n }\n\n <!-- Configuration Controls -->\n @if (shouldShowConfigControls && enableCustomization) {\n <div class=\"form-config-controls\">\n @if (showAiAssistant) {\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"dense\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('config-controls')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Abrir copiloto sem\u00E2ntico do formul\u00E1rio\">\n </button>\n }\n <button type=\"button\" praxisIconButton=\"settings\" size=\"dense\" (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [attr.aria-label]=\"configControlLabel\" [matTooltip]=\"configControlLabel\">\n </button>\n <button type=\"button\" praxisIconButton=\"link_off\" size=\"dense\" (click)=\"disconnect()\"\n [attr.aria-label]=\"disconnectControlLabel\" [matTooltip]=\"disconnectControlLabel\"\n [disabled]=\"isLoading\">\n </button>\n </div>\n }\n\n <!-- Form Content -->\n @if (!resourcePath && !hasExplicitSchemaUrl() && !hasRenderableConfig()) {\n <praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n }\n @if (shouldShowContextEmptyState()) {\n <div class=\"form-context-empty-state\" role=\"status\" aria-live=\"polite\">\n <praxis-empty-state-card\n [icon]=\"emptyState?.icon || 'touch_app'\"\n [title]=\"emptyState!.title\"\n [description]=\"emptyState?.description\"\n [tone]=\"emptyState?.tone || 'primary'\"\n [variant]=\"emptyState?.variant || 'transparent'\"\n [alignment]=\"emptyState?.alignment || 'center'\"\n [density]=\"emptyState?.density || 'compact'\"\n [iconContainer]=\"emptyState?.iconContainer || 'circle'\"\n [inline]=\"true\"\n />\n </div>\n } @else {\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n @if (enableCustomization && selectedElement) {\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n }\n\n @if (formBlocksBefore?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of (config.sections || []); track (section.id ?? $index); let sectionIndex = $index) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!isLastVisibleSection(section) ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n [class.title-only]=\"isSectionHeaderTitleOnly(section)\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getEffectiveSectionTitleGapBottom(section)\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\" (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\"\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n [praxisIconButton]=\"action.icon\"\n size=\"compact\"\n [busy]=\"action.loading\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" [praxisIconButton]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\" size=\"compact\"\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.role]=\"getSectionTitle(section) ? 'region' : null\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column, row)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n @for (renderItem of getColumnRenderItems(column); track renderItem.id) {\n @if (renderItem.kind === 'fields') {\n <ng-container dynamicFieldLoader [fields]=\"getRenderableFieldsForLoader(renderItem.fields)\" [formGroup]=\"form\"\n [enableExternalControlBinding]=\"true\"\n [readonlyMode]=\"effectiveReadonly\"\n [disabledMode]=\"effectiveDisabledMode\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (canvasFocus)=\"onFieldFocus($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n } @else {\n <praxis-rich-content\n class=\"form-layout-rich-content\"\n [ngClass]=\"renderItem.className || null\"\n [ngStyle]=\"renderItem.style || null\"\n [document]=\"renderItem.document\"\n [layout]=\"renderItem.layout\"\n [rootClassName]=\"renderItem.rootClassName || ''\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n }\n }\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (isLastVisibleSection(section) && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && isLastVisibleSection(section) && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"effectiveActions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner\n diameter=\"40\"\n color=\"primary\"\n [attr.aria-label]=\"config.messages?.loading?.submit || 'Salvando formul\u00E1rio'\"\n ></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n <praxis-rich-content\n [document]=\"formBlocksAfterDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n </form>\n }\n @if (showAiAssistant && !enableCustomization && mode === 'view' && !shouldShowContextEmptyState()) {\n <div class=\"ai-floating-assistant\">\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"compact\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('view-floating')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Pedir ajuda sobre este formul\u00E1rio\">\n </button>\n </div>\n }\n @if (showAiAssistant && 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]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"dynamic-form-ai-assistant\"\n panelTestId=\"dynamic-form-ai-assistant-panel\"\n submitTestId=\"dynamic-form-ai-assistant-submit\"\n applyTestId=\"dynamic-form-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", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@container praxis-form-row (min-width: 600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@container praxis-form-row (min-width: 900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@container praxis-form-row (min-width: 1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@container praxis-form-row (min-width: 1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative;--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--pdx-color-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent );--pfx-form-shell-padding: clamp(.9rem, 1.4vw, 1.2rem)}.form-config-controls{position:relative;top:auto;margin:0;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--pfx-form-shell-surface) 88%,var(--md-sys-color-surface) 12%);padding:8px var(--pfx-form-shell-padding);border:1px solid var(--pfx-form-footer-border);border-bottom-color:color-mix(in srgb,var(--pfx-form-footer-border) 72%,transparent);border-radius:var(--pfx-editorial-form-radius) var(--pfx-editorial-form-radius) 0 0;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:none;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.96;transition:opacity .16s ease,border-color .16s ease}.form-config-controls>*{pointer-events:auto}.form-config-controls:hover,.form-config-controls:focus-within{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%)}.form-config-controls .praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}.form-config-controls .praxis-icon-button:hover{color:var(--md-sys-color-primary)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant button{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:stretch;justify-content:center;padding:1.25rem;text-align:left;color:var(--md-sys-color-on-surface);gap:1rem;min-height:220px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 14%,var(--md-sys-color-outline-variant) 86%);border-radius:8px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 8%,transparent),transparent 42%),color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,var(--md-sys-color-surface) 22%);box-shadow:0 12px 28px #0f172a14}.form-loading-header{display:flex;align-items:center;gap:.85rem}.form-loading-copy{min-width:0}.form-loading p{margin:0}.form-loading-title{font-weight:700;color:var(--md-sys-color-on-surface)}.form-loading-subtitle{margin-top:.2rem;font-size:.875rem;color:var(--md-sys-color-on-surface-variant)}.form-loading-skeleton{display:grid;gap:.7rem}.form-loading-line,.form-loading-field{display:block;overflow:hidden;position:relative;border-radius:6px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 74%,var(--md-sys-color-primary) 6%)}.form-loading-line:after,.form-loading-field:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--md-sys-color-primary) 16%,white 18%),transparent);animation:form-loading-shimmer 1.4s ease-in-out infinite}.form-loading-line{height:12px}.form-loading-line-title{width:min(42%,240px)}.form-loading-line-short{width:min(64%,360px)}.form-loading-field{height:44px}.form-loading-field-wide{height:72px}@keyframes form-loading-shimmer{to{transform:translate(100%)}}@media(prefers-reduced-motion:reduce){.form-loading-line:after,.form-loading-field:after{animation:none;transform:none;opacity:.28}}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;max-width:100%;min-width:0;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --pdx-color-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --pdx-color-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var( --pdx-color-primary, var(--md-sys-color-primary) );--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pdx-presentation-label-size: var(--pfx-pres-compact-label-size, .78rem);--pdx-presentation-value-size: var(--pfx-pres-compact-value-size, 1rem);--pdx-presentation-icon-size: var(--pfx-pres-icon-size, 18px);--pdx-presentation-row-gap: var(--pfx-pres-row-gap, .5rem);--pdx-presentation-column-gap: var(--pfx-pres-column-gap, .5rem);--pdx-presentation-section-gap: var(--pfx-pres-section-gap, .75rem);--pdx-presentation-label-width: var(--pfx-pres-label-width, 220px);--pdx-presentation-flag-height: var(--pfx-pres-boolean-min-height, 22px);--pdx-presentation-flag-radius: var(--pfx-pres-boolean-radius, 999px);--pdx-presentation-flag-padding: var(--pfx-pres-boolean-padding, 0 8px);--pdx-presentation-flag-active-color: var( --pfx-pres-boolean-active-color, var(--md-sys-color-primary) );--pdx-presentation-flag-active-bg: var( --pfx-pres-boolean-active-bg, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent) );--pdx-presentation-flag-inactive-color: var( --pfx-pres-boolean-inactive-color, var(--md-sys-color-on-surface-variant) );--pdx-presentation-flag-inactive-bg: var( --pfx-pres-boolean-inactive-bg, color-mix(in srgb, var(--md-sys-color-outline-variant) 34%, transparent) );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.canvas-mode-enabled{border:1px solid var(--pfx-form-footer-border);border-radius:var(--pfx-editorial-form-radius);background:linear-gradient(180deg,color-mix(in srgb,var(--pfx-form-shell-surface) 86%,transparent),color-mix(in srgb,var(--pfx-editorial-form-surface-muted) 42%,transparent));overflow:visible}.form-config-controls+.praxis-dynamic-form.canvas-mode-enabled{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks{margin-inline:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper:first-of-type,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks:first-child{margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>praxis-form-actions[data-actions-placement=afterSections]{display:block;margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.editorial-visual-context{--_pfx-editorial-host-text: var( --editorial-text-primary, var(--foreground, var(--mat-sys-on-surface, #1d1b20)) );--_pfx-editorial-host-text-muted: var( --editorial-text-secondary, var( --muted-foreground, color-mix(in srgb, var(--_pfx-editorial-host-text) 64%, transparent) ) );--_pfx-editorial-host-surface: var( --editorial-surface-primary, var(--card, var(--mat-sys-surface-container, #ffffff)) );--_pfx-editorial-host-surface-muted: var( --editorial-surface-secondary, var(--surface-dim, var(--muted, var(--mat-sys-surface-container-low, #f7f2fa))) );--_pfx-editorial-host-border: var( --editorial-border-color, var(--border, var(--mat-sys-outline-variant, #cac4d0)) );--_pfx-editorial-host-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--primary, var(--mat-sys-primary, #6750a4))) );--_pfx-editorial-host-accent-text: var( --editorial-cta-primary-text, var( --editorial-accent-contrast, var(--primary-foreground, var(--mat-sys-on-primary, #ffffff)) ) );--_pfx-editorial-host-accent-container: var( --primary-container, color-mix(in srgb, var(--_pfx-editorial-host-accent) 16%, var(--_pfx-editorial-host-surface) 84%) );--_pfx-editorial-host-accent-container-text: var( --primary-container-fg, var(--_pfx-editorial-host-accent) );font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--_pfx-editorial-host-text);--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--_pfx-editorial-host-surface)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--_pfx-editorial-host-surface-muted) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--_pfx-editorial-host-border)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--_pfx-editorial-host-text) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, color-mix( in srgb, var(--_pfx-editorial-host-text-muted) 86%, var(--_pfx-editorial-host-text) 14% ) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--_pfx-editorial-host-accent)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--_pfx-editorial-host-accent-text)) );--pfx-editorial-form-accent-container: var(--_pfx-editorial-host-accent-container);--pfx-editorial-form-accent-container-text: var(--_pfx-editorial-host-accent-container-text);--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --editorial-text-primary, inherit );--md-sys-color-on-surface-variant: var( --editorial-text-secondary, inherit );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-primary-container: var( --pfx-editorial-form-accent-container, var(--md-sys-color-primary-container) );--md-sys-color-on-primary-container: var( --pfx-editorial-form-accent-container-text, var(--md-sys-color-on-primary-container) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );--mat-sys-on-surface: var( --editorial-text-primary, inherit );--mat-sys-on-surface-variant: var( --editorial-text-secondary, inherit );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );color:inherit;color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:var(--pdx-presentation-column-gap);margin-bottom:var(--pdx-presentation-row-gap)}.praxis-dynamic-form.presentation-mode{--pfx-pres-on-surface: var( --pdx-color-text-primary, var(--pfx-editorial-form-text, var(--pfx-form-label-strong, currentColor)) );--pfx-pres-on-surface-variant: var( --pdx-color-text-secondary, var( --pfx-editorial-form-text-muted, var( --pfx-form-label-muted, color-mix(in srgb, var(--pfx-pres-on-surface) 78%, transparent) ) ) )}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:var(--pdx-presentation-section-gap) .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:var(--pdx-presentation-column-gap, .35rem);margin-bottom:var(--pdx-presentation-row-gap, .35rem)}.praxis-dynamic-form.pres-compact .form-section{padding:var(--pdx-presentation-section-gap, .5rem) .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:minmax(0,var(--pfx-presentation-label-w, var(--pdx-presentation-label-width))) minmax(0,1fr);align-items:baseline;column-gap:var(--pdx-presentation-column-gap, 10px)}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}@media(max-width:480px){.praxis-dynamic-form.pres-label-left .praxis-presentation{grid-template-columns:minmax(0,1fr);row-gap:4px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:start}}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);max-width:100%;min-width:0;background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section{border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;color:var(--pfx-editorial-form-text);box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{position:relative;display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 18px)}.section-heading:after{content:\"\";position:absolute;right:0;bottom:0;left:0;height:2px;pointer-events:none;background:linear-gradient(90deg,transparent 0%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 8%,var(--pfx-form-section-divider) 46%,var(--pfx-form-section-divider) 54%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 92%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%);mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 10px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:none}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn.tone-primary{color:var(--md-sys-color-primary)}.section-heading-action-btn.tone-accent,.section-heading-action-btn.tone-secondary{color:var(--md-sys-color-tertiary)}.section-heading-action-btn.tone-warn,.section-heading-action-btn.tone-danger,.section-heading-action-btn.tone-error{color:var(--md-sys-color-error)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 16px)}.form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 16px)}:host(.pfx-form-section-divider-inline-title) .form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form:not(.canvas-mode-enabled)>praxis-form-actions[data-actions-placement=afterSections]{margin-top:18px}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);max-width:100%;min-width:0;transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=entityLookup],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;grid-template-columns:minmax(0,1fr);align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;max-width:100%;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-layout-rich-content{display:block;width:100%;max-width:100%;min-width:0;margin-bottom:var(--pfx-field-gap, 10px);color:var(--pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant));font:var(--mdc-typography-body-medium, 400 14px/20px system-ui);overflow-wrap:anywhere}:host ::ng-deep .form-layout-rich-content .prx-rich-content-root{display:grid;gap:8px;min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-node{min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-text{color:inherit;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{border:1px solid color-mix(in srgb,var(--pfx-editorial-form-accent) 12%,var(--pfx-editorial-form-border) 88%);border-left:3px solid var(--pfx-editorial-form-accent);border-radius:8px;background:color-mix(in srgb,var(--pfx-editorial-form-accent-container) 12%,var(--pfx-editorial-form-surface-muted) 88%)}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:flex-start;padding:11px 12px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note:before{content:\"info\";display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;color:var(--pfx-editorial-form-accent);font-family:Material Symbols Outlined;font-size:20px;font-weight:400;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{padding:10px 12px;color:var(--pfx-editorial-form-text)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-compose{align-items:flex-start;gap:10px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-icon{color:var(--pfx-editorial-form-accent);font-size:20px;line-height:20px;margin-top:1px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider{display:grid;grid-template-columns:minmax(24px,1fr) auto minmax(24px,1fr);align-items:center;gap:10px;color:var(--pfx-editorial-form-text-muted);font:var(--mdc-typography-label-small, 600 12px/16px system-ui);text-transform:uppercase}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:before,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:after{content:\"\";height:1px;background:var(--pfx-editorial-form-border)}:host ::ng-deep .form-layout-rich-content .prx-rich-card{gap:6px;padding:12px 14px;border-color:var(--pfx-editorial-form-border);border-radius:8px;background:var(--pfx-editorial-form-surface-muted);color:var(--pfx-editorial-form-text);box-shadow:none}:host ::ng-deep .form-layout-rich-content .prx-rich-card-title{color:var(--pfx-editorial-form-text);font:var(--mdc-typography-title-small, 600 14px/20px system-ui)}:host ::ng-deep .form-layout-rich-content .prx-rich-card-subtitle,:host ::ng-deep .form-layout-rich-content .prx-rich-metric-caption{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-card .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-badge{background:var(--pfx-editorial-form-accent-container);color:var(--pfx-editorial-form-accent-container-text)}.form-row.grid-12{container-type:inline-size;container-name:praxis-form-row;display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.column-drop-wrapper,.row-drop-wrapper,.form-layout-rich-content,.praxis-dynamic-form .mat-mdc-form-field,.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{max-width:100%;min-width:0}:host ::ng-deep .praxis-dynamic-form .pfx-field-shell,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-wrapper,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-host,:host ::ng-deep .praxis-dynamic-form .mat-mdc-form-field,:host ::ng-deep .praxis-dynamic-form .mat-mdc-text-field-wrapper,:host ::ng-deep .praxis-dynamic-form .mdc-text-field{width:100%;max-width:100%;min-width:0}.form-section{padding:clamp(.75rem,4vw,1rem)}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 14px)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}}.section-title{display:flex;align-items:center;gap:8px}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:100%;min-width:0}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{content:\"\";display:block;flex:1 1 auto;min-width:var(--pfx-form-section-title-inline-divider-min-width, 48px);height:2px;margin-left:var(--pfx-form-section-title-inline-divider-gap, 12px);pointer-events:none;background:linear-gradient(90deg,var(--pfx-form-section-divider) 0%,var(--pfx-form-section-divider) 62%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 88%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%);mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%)}:host(.pfx-form-section-divider-inline-title) .section-heading.align-center .section-title:after{display:none}@media(max-width:640px){:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:block}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:auto}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{display:none}}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.form-context-empty-state{display:grid;min-height:var(--pdx-form-context-empty-min-height, clamp(9.25rem, 20vh, 14rem));place-items:center;padding:var(--pdx-form-context-empty-padding, clamp(1.5rem, 3vw, 2.5rem))}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}\n"] }]
20590
+ ], template: "@if (isLoading) {\n <!-- Loading State -->\n <div class=\"form-loading\" role=\"status\" aria-live=\"polite\" aria-label=\"Carregando formul\u00E1rio\">\n <div class=\"form-loading-header\">\n <mat-progress-spinner diameter=\"32\" aria-label=\"Carregando formul\u00E1rio\"></mat-progress-spinner>\n <div class=\"form-loading-copy\">\n <p class=\"form-loading-title\">Carregando formul\u00E1rio...</p>\n <p class=\"form-loading-subtitle\">Preparando campos e op\u00E7\u00F5es do cadastro.</p>\n </div>\n </div>\n <div class=\"form-loading-skeleton\" aria-hidden=\"true\">\n <span class=\"form-loading-line form-loading-line-title\"></span>\n <span class=\"form-loading-line\"></span>\n <span class=\"form-loading-line form-loading-line-short\"></span>\n <span class=\"form-loading-field\"></span>\n <span class=\"form-loading-field form-loading-field-wide\"></span>\n </div>\n </div>\n} @else if (initializationStatus === 'error') {\n <!-- Error State -->\n <div class=\"form-error\">\n <mat-icon color=\"warn\" [praxisIcon]=\"'error'\"></mat-icon>\n <h3>{{ getErrorTitle() }}</h3>\n <p>{{ currentErrorMessage }}</p>\n @if (isRecoverable) {\n <button mat-stroked-button (click)=\"retryInitialization()\">\n <mat-icon [praxisIcon]=\"'refresh'\"></mat-icon>\n Tentar Novamente\n </button>\n }\n <button mat-button (click)=\"showDetailedError()\" class=\"show-details\">\n Ver Detalhes T\u00E9cnicos\n </button>\n <!-- Permitir corre\u00E7\u00E3o do resourcePath diretamente do estado de erro -->\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\" class=\"connect-action\">\n <mat-icon [praxisIcon]=\"'bolt'\"></mat-icon>\n Conectar a recurso\n </button>\n </div>\n} @else if (initializationStatus === 'success') {\n <!-- Inline banner for schema change (only when customization is enabled) -->\n @if (shouldShowOutdatedInline()) {\n <div class=\"pfx-form-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"openConfigEditor()\">\n <mat-icon [praxisIcon]=\"'sync'\"></mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n }\n\n <!-- Configuration Controls -->\n @if (shouldShowConfigControls && enableCustomization) {\n <div class=\"form-config-controls\">\n @if (showAiAssistant) {\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"dense\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('config-controls')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Abrir copiloto sem\u00E2ntico do formul\u00E1rio\">\n </button>\n }\n <button type=\"button\" praxisIconButton=\"settings\" size=\"dense\" (click)=\"openConfigEditor()\" [disabled]=\"isLoading\" class=\"config-button\"\n [matBadge]=\"schemaOutdated ? '!' : ''\" [matBadgeHidden]=\"!schemaOutdated\" matBadgeColor=\"warn\" matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [attr.aria-label]=\"configControlLabel\" [matTooltip]=\"configControlLabel\">\n </button>\n <button type=\"button\" praxisIconButton=\"link_off\" size=\"dense\" (click)=\"disconnect()\"\n [attr.aria-label]=\"disconnectControlLabel\" [matTooltip]=\"disconnectControlLabel\"\n [disabled]=\"isLoading\">\n </button>\n </div>\n }\n\n <!-- Form Content -->\n @if (!resourcePath && !hasExplicitSchemaUrl() && !hasRenderableConfig()) {\n <praxis-empty-state-card icon=\"link\" [title]=\"'Conecte o formul\u00E1rio \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para gerar automaticamente os campos do formul\u00E1rio.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"></praxis-empty-state-card>\n }\n @if (shouldShowContextEmptyState()) {\n <div class=\"form-context-empty-state\" role=\"status\" aria-live=\"polite\">\n <praxis-empty-state-card\n [icon]=\"emptyState?.icon || 'touch_app'\"\n [title]=\"emptyState!.title\"\n [description]=\"emptyState?.description\"\n [tone]=\"emptyState?.tone || 'primary'\"\n [variant]=\"emptyState?.variant || 'transparent'\"\n [alignment]=\"emptyState?.alignment || 'center'\"\n [density]=\"emptyState?.density || 'compact'\"\n [iconContainer]=\"emptyState?.iconContainer || 'circle'\"\n [inline]=\"true\"\n />\n </div>\n } @else {\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\" [class.readonly-mode]=\"effectiveReadonly\"\n [class.editorial-visual-context]=\"hasEditorialVisualContext()\"\n [class.pfx-mounting]=\"isMounting\" [formGroup]=\"form\"\n [ngClass]=\"{\n 'pres-compact': presentationVars.compact,\n 'pres-label-left': presentationVars.labelPosition === 'left',\n 'pres-label-above': presentationVars.labelPosition === 'above'\n }\" [style.--pfx-pres-label-align]=\"presentationVars.labelAlign\"\n [style.--pfx-pres-label-size]=\"presentationVars.labelSize\"\n [style.--pfx-pres-label-width]=\"presentationVars.labelWidth\"\n [style.--pfx-pres-row-gap]=\"presentationVars.density === 'compact' ? '6px' : (presentationVars.density === 'cozy' ? '8px' : '10px')\"\n [style.--pfx-pres-row-padding]=\"presentationVars.density === 'compact' ? '2px 0' : (presentationVars.density === 'cozy' ? '6px 0' : '8px 0')\"\n [style.--pfx-pres-value-align]=\"presentationVars.valueAlign\"\n [style.--pfx-pres-value-size]=\"presentationVars.valueSize\"\n [style.--pdx-form-mount-duration]=\"getMountDurationVar()\"\n [style.--pdx-form-mount-offset]=\"getMountOffsetVar()\"\n [style.--pdx-form-mount-stagger]=\"getMountStaggerVar()\"\n class=\"praxis-dynamic-form\">\n @if (enableCustomization && selectedElement) {\n <praxis-canvas-toolbar (editMetadata)=\"openSelectedElementEditor()\" (selectPath)=\"onSelectPath($event)\"\n (moveUp)=\"onToolbarMove('up')\" (moveDown)=\"onToolbarMove('down')\" (toggleReadonly)=\"onToolbarToggleReadonly()\"\n (toggleRequired)=\"onToolbarToggleRequired()\" (toggleHidden)=\"onToolbarToggleHidden()\"\n (toggleDisabled)=\"onToolbarToggleDisabled()\" (requestClose)=\"onToolbarRequestClose()\"\n [selectedElement]=\"selectedElement\"\n [style.transform]=\"toolbarTransform\"></praxis-canvas-toolbar>\n }\n\n @if (formBlocksBefore?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before\" data-editorial-placement=\"before\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'top' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"top\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\" [actionOverrides]=\"actionRuleProps\"\n [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @for (section of (config.sections || []); track (section.id ?? $index); let sectionIndex = $index) {\n <div class=\"section-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n @if (isSectionVisible(section)) {\n <div #sectionEl class=\"form-section canvas-element\" data-canvas-type=\"section\" [attr.data-section-id]=\"section.id\"\n [attr.data-section-index]=\"sectionIndex\" (mouseenter)=\"onElementMouseEnter($event, 'section', section, sectionEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'section', section, sectionEl)\"\n [class.selected]=\"selectedElement?.domElement === sectionEl\"\n [class.hovered]=\"hoveredElement?.domElement === sectionEl && selectedElement?.domElement !== sectionEl\"\n [attr.data-section-appearance]=\"getSectionAppearance(section) || null\"\n [style.marginBottom.px]=\"!isLastVisibleSection(section) ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n <div\n class=\"section-heading\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [class.step-appearance]=\"getSectionAppearance(section) === 'step'\"\n [class.title-only]=\"isSectionHeaderTitleOnly(section)\"\n >\n <div class=\"section-heading-text\" [matTooltip]=\"getSectionHeaderTooltip(section) || null\"\n [matTooltipDisabled]=\"!getSectionHeaderTooltip(section)\">\n @if (getSectionStepLabel(section)) {\n <div class=\"section-step-label\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionStepLabel(section) }}\n </div>\n }\n @if (getSectionTitle(section)) {\n <h3 class=\"section-title\" [class.title-large]=\"getSectionTitleStyle(section) === 'titleLarge'\"\n [class.title-medium]=\"getSectionTitleStyle(section) === 'titleMedium'\"\n [class.title-small]=\"getSectionTitleStyle(section) === 'titleSmall'\"\n [class.headline-small]=\"getSectionTitleStyle(section) === 'headlineSmall'\"\n [style.marginBottom.px]=\"getEffectiveSectionTitleGapBottom(section)\" [style.color]=\"getSectionTitleColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\"\n [attr.id]=\"sectionPanelId(section, sectionIndex) + '-title'\">\n @let sectionHeaderVisual = getSectionHeaderVisual(section);\n @let sectionHeaderAvatarSize = getSectionHeaderAvatarSize(section);\n @if (sectionHeaderVisual.kind === 'icon') {\n <mat-icon class=\"section-title-icon\" aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.kind === 'image') {\n <img class=\"section-title-avatar section-title-avatar-image\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\"\n [src]=\"sectionHeaderVisual.src\" [alt]=\"sectionHeaderVisual.alt\" />\n }\n @if (sectionHeaderVisual.kind === 'initials') {\n <span class=\"section-title-avatar section-title-avatar-text\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n {{ sectionHeaderVisual.text }}\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n @if (sectionHeaderVisual.kind === 'placeholder') {\n <span class=\"section-title-avatar section-title-avatar-placeholder\" [class.size-sm]=\"sectionHeaderAvatarSize === 'sm'\"\n [class.size-md]=\"sectionHeaderAvatarSize === 'md'\" [class.size-lg]=\"sectionHeaderAvatarSize === 'lg'\" aria-hidden=\"true\">\n @if (sectionHeaderVisual.icon) {\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"sectionHeaderVisual.icon\"></mat-icon>\n }\n @if (sectionHeaderVisual.text) {\n <span>{{ sectionHeaderVisual.text }}</span>\n }\n </span>\n @if (sectionHeaderVisual.ariaLabel) {\n <span class=\"section-title-avatar-sr-only\">{{ sectionHeaderVisual.ariaLabel }}</span>\n }\n }\n {{ getSectionTitle(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\" (click)=\"openSectionEditor(section, 'title')\"\n aria-label=\"Editar t\u00EDtulo da se\u00E7\u00E3o\" matTooltip=\"Editar t\u00EDtulo\">\n </button>\n }\n </h3>\n }\n @if (getSectionDescription(section)) {\n <p class=\"section-description\" [class.body-large]=\"getSectionDescriptionStyle(section) === 'bodyLarge'\"\n [class.body-medium]=\"getSectionDescriptionStyle(section) === 'bodyMedium'\"\n [class.body-small]=\"getSectionDescriptionStyle(section) === 'bodySmall'\"\n [style.marginBottom.px]=\"getSectionDescriptionGapBottom(section) ?? 8\" [style.color]=\"getSectionDescriptionColor(section) || null\"\n [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n {{ getSectionDescription(section) }}\n @if (enableCustomization) {\n <button type=\"button\" class=\"inline-edit-btn\" praxisIconButton=\"edit\" size=\"dense\"\n (click)=\"openSectionEditor(section, 'description')\" aria-label=\"Editar descri\u00E7\u00E3o da se\u00E7\u00E3o\"\n matTooltip=\"Editar descri\u00E7\u00E3o\">\n </button>\n }\n </p>\n }\n </div>\n @if (getSectionHeaderActions(section).length) {\n <div class=\"section-heading-actions\" [class.align-center]=\"getSectionHeaderAlign(section) === 'center'\">\n @for (action of getSectionHeaderActions(section); track action.id) {\n <button\n type=\"button\"\n class=\"section-heading-action-btn\"\n [praxisIconButton]=\"action.icon\"\n size=\"compact\"\n [busy]=\"action.loading\"\n [disabled]=\"isSectionHeaderActionDisabled(action)\"\n [matTooltip]=\"getSectionHeaderActionTooltip(action)\"\n [attr.aria-label]=\"action.label\"\n [attr.aria-busy]=\"action.loading ? 'true' : null\"\n [ngClass]=\"getSectionHeaderActionNgClass(action)\"\n [ngStyle]=\"getSectionHeaderActionStyles(action)\"\n (click)=\"onSectionHeaderActionClick(section, action, $event)\"\n >\n @if (action.loading) {\n <span class=\"section-heading-action-sr-only\">{{ getSectionHeaderActionLoadingLabel(action) }}</span>\n }\n </button>\n }\n </div>\n }\n @if (isSectionCollapsible(section)) {\n <button type=\"button\" class=\"section-collapse-btn\" [praxisIconButton]=\"isSectionCollapsed(section) ? 'expand_more' : 'expand_less'\" size=\"compact\"\n (click)=\"toggleSectionCollapse($event, section)\" [attr.aria-expanded]=\"!isSectionCollapsed(section)\"\n [attr.aria-controls]=\"sectionPanelId(section, sectionIndex)\"\n [attr.aria-label]=\"isSectionCollapsed(section) ? 'Expandir se\u00E7\u00E3o' : 'Recolher se\u00E7\u00E3o'\">\n </button>\n }\n </div>\n\n <div class=\"section-body\" [class.collapsed]=\"isSectionCollapsed(section)\"\n [attr.id]=\"sectionPanelId(section, sectionIndex)\"\n [attr.role]=\"getSectionTitle(section) ? 'region' : null\"\n [attr.aria-labelledby]=\"getSectionTitle(section) ? sectionPanelId(section, sectionIndex) + '-title' : null\">\n @if (!isSectionCollapsed(section)) {\n @for (row of section.rows; track (row.id ?? $index); let rowIndex = $index) {\n @if (isRowVisible(row)) {\n <div class=\"row-drop-wrapper\" [attr.data-section-id]=\"section.id\">\n <div #rowEl class=\"form-row grid-12 canvas-element\" data-canvas-type=\"row\" [attr.data-row-index]=\"rowIndex\"\n [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\" [style.--pfx-grid-gap.px]=\"getRowGap(row)\"\n [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [style.--pfx-mount-index]=\"rowIndex\"\n [style.marginBottom.px]=\"rowIndex < section.rows.length - 1 ? (getRowRowGap(row) ?? null) : null\"\n [ngClass]=\"getRowClasses(row)\" [ngStyle]=\"getRowStyles(row)\"\n (mouseenter)=\"onElementMouseEnter($event, 'row', row, rowEl)\" (mouseleave)=\"onElementMouseLeave($event)\"\n (click)=\"onElementClick($event, 'row', row, rowEl)\" [class.selected]=\"selectedElement?.domElement === rowEl\"\n [class.hovered]=\"hoveredElement?.domElement === rowEl && selectedElement?.domElement !== rowEl\">\n @for (column of row.columns; track (column.id ?? $index); let colIndex = $index) {\n @if (isColumnVisible(column)) {\n <div class=\"column-drop-wrapper\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\">\n <div #colEl class=\"form-column canvas-element\" [ngClass]=\"getColumnClasses(column, row)\"\n [style.padding.px]=\"getColumnPadding(column)\" [style.--pfx-field-gap.px]=\"getRowRowGap(row)\"\n [ngStyle]=\"getColumnStyles(column)\" [attr.data-testid]=\"column.testId || null\"\n [attr.data-row-gap]=\"getRowRowGap(row)\" data-canvas-type=\"column\" [attr.data-column-index]=\"colIndex\"\n [attr.data-row-index]=\"rowIndex\" [attr.data-section-id]=\"section.id\" [attr.data-row-id]=\"row.id\"\n [attr.data-column-id]=\"column.id\" (mouseenter)=\"onElementMouseEnter($event, 'column', column, colEl)\"\n (mouseleave)=\"onElementMouseLeave($event)\" (click)=\"onElementClick($event, 'column', column, colEl)\"\n [class.selected]=\"selectedElement?.domElement === colEl\"\n [class.hovered]=\"hoveredElement?.domElement === colEl && selectedElement?.domElement !== colEl\">\n @for (renderItem of getColumnRenderItems(column); track renderItem.id) {\n @if (renderItem.kind === 'fields') {\n <ng-container dynamicFieldLoader [fields]=\"getRenderableFieldsForLoader(renderItem.fields)\" [formGroup]=\"form\"\n [enableExternalControlBinding]=\"true\"\n [readonlyMode]=\"effectiveReadonly\"\n [disabledMode]=\"effectiveDisabledMode\"\n [presentationMode]=\"presentationForLoader\" [visible]=\"visibleGlobal === null ? null : visibleGlobal\"\n [canvasMode]=\"enableCustomization\" (canvasMouseEnter)=\"onFieldMouseEnter($event)\"\n (canvasMouseLeave)=\"onFieldMouseLeave($event)\" (canvasClick)=\"onFieldClick($event)\"\n (canvasFocus)=\"onFieldFocus($event)\"\n (renderError)=\"onFieldRenderError($event)\">\n </ng-container>\n } @else {\n <praxis-rich-content\n class=\"form-layout-rich-content\"\n [ngClass]=\"renderItem.className || null\"\n [ngStyle]=\"renderItem.style || null\"\n [document]=\"renderItem.document\"\n [layout]=\"renderItem.layout\"\n [rootClassName]=\"renderItem.rootClassName || ''\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n }\n }\n </div>\n </div>\n } }\n </div>\n </div>\n }\n }\n } @else {\n <div class=\"section-collapsed-placeholder\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'unfold_more'\"></mat-icon>\n <span>{{ getSectionCollapsedSummary(section) }}</span>\n </div>\n }\n @if (isLastVisibleSection(section) && beforeActionsPlacement === 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n @if (actionPlacement === 'insideLastSection' && isLastVisibleSection(section) && !(effectivePresentation\n || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"insideLastSection\" [actions]=\"effectiveActions\"\n [isSubmitting]=\"submitting\" [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n </div>\n <!-- Overlay de bloqueio durante submiss\u00E3o -->\n @if (submitting) {\n <div class=\"form-blocking-overlay\" aria-live=\"polite\">\n <mat-progress-spinner\n diameter=\"40\"\n color=\"primary\"\n [attr.aria-label]=\"config.messages?.loading?.submit || 'Salvando formul\u00E1rio'\"\n ></mat-progress-spinner>\n <p>{{ config.messages?.loading?.submit || 'Salvando...' }}</p>\n </div>\n }\n </div>\n\n @if (enableCustomization && selectedElement?.domElement === sectionEl) {\n <div class=\"add-section-container\">\n <div class=\"add-section-line\"></div>\n <button mat-fab color=\"primary\" aria-label=\"Adicionar nova se\u00E7\u00E3o\" (click)=\"addNewSectionAfter(sectionIndex)\"\n matTooltip=\"Adicionar nova se\u00E7\u00E3o aqui\">\n <mat-icon [praxisIcon]=\"'add'\"></mat-icon>\n </button>\n <div class=\"add-section-line\"></div>\n </div>\n }\n }\n </div>\n }\n\n @if (beforeActionsPlacement !== 'insideLastSection' && formBlocksBeforeActions?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-before-actions\" data-editorial-placement=\"beforeActions\">\n <praxis-rich-content\n [document]=\"formBlocksBeforeActionsDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n\n @if (actionPlacement === 'afterSections' && !(effectivePresentation || effectiveReadonly)) {\n <praxis-form-actions data-actions-placement=\"afterSections\" [actions]=\"effectiveActions\" [isSubmitting]=\"submitting\"\n [formIsValid]=\"effectiveFormIsValid\" [submitError]=\"submitError\" [formId]=\"formId\"\n [actionOverrides]=\"actionRuleProps\" [invalidRequiredFieldLabels]=\"invalidRequiredFieldLabels\"\n [suppressInvalidSubmitHint]=\"entityHydrationPending\"\n [editorialVisualContext]=\"hasEditorialVisualContext()\"\n (action)=\"onFormAction($event)\"></praxis-form-actions>\n }\n\n @if (formBlocksAfter?.nodes?.length) {\n <section class=\"form-editorial-blocks form-editorial-blocks-after\" data-editorial-placement=\"after\">\n <praxis-rich-content\n [document]=\"formBlocksAfterDocument\"\n [context]=\"getEditorialRichContentContext()\"\n [hostCapabilities]=\"richContentHostCapabilities\"\n ></praxis-rich-content>\n </section>\n }\n </form>\n }\n @if (showAiAssistant && !enableCustomization && mode === 'view' && !shouldShowContextEmptyState()) {\n <div class=\"ai-floating-assistant\">\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"compact\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading\"\n [attr.data-testid]=\"aiAssistantTriggerTestId('view-floating')\"\n aria-label=\"Abrir copiloto semantico Praxis do formulario\"\n matTooltip=\"Pedir ajuda sobre este formul\u00E1rio\">\n </button>\n </div>\n }\n @if (showAiAssistant && 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]=\"aiAssistantViewState.state === 'processing' || aiAssistantViewState.state === 'applying'\"\n [canApply]=\"aiAssistantViewState.canApply\"\n [layout]=\"aiAssistantLayout\"\n testIdPrefix=\"dynamic-form-ai-assistant\"\n panelTestId=\"dynamic-form-ai-assistant-panel\"\n submitTestId=\"dynamic-form-ai-assistant-submit\"\n applyTestId=\"dynamic-form-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", styles: ["@charset \"UTF-8\";.span-xs-1{grid-column:span 1}.span-xs-2{grid-column:span 2}.span-xs-3{grid-column:span 3}.span-xs-4{grid-column:span 4}.span-xs-5{grid-column:span 5}.span-xs-6{grid-column:span 6}.span-xs-7{grid-column:span 7}.span-xs-8{grid-column:span 8}.span-xs-9{grid-column:span 9}.span-xs-10{grid-column:span 10}.span-xs-11{grid-column:span 11}.span-xs-12{grid-column:span 12}.offset-xs-0{margin-left:0%}.offset-xs-1{margin-left:calc(1 / 12 * 100%)}.offset-xs-2{margin-left:calc(2 / 12 * 100%)}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:calc(4 / 12 * 100%)}.offset-xs-5{margin-left:calc(5 / 12 * 100%)}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:calc(7 / 12 * 100%)}.offset-xs-8{margin-left:calc(8 / 12 * 100%)}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:calc(10 / 12 * 100%)}.offset-xs-11{margin-left:calc(11 / 12 * 100%)}.order-xs--12{order:-12}.order-xs--11{order:-11}.order-xs--10{order:-10}.order-xs--9{order:-9}.order-xs--8{order:-8}.order-xs--7{order:-7}.order-xs--6{order:-6}.order-xs--5{order:-5}.order-xs--4{order:-4}.order-xs--3{order:-3}.order-xs--2{order:-2}.order-xs--1{order:-1}.order-xs-0{order:0}.order-xs-1{order:1}.order-xs-2{order:2}.order-xs-3{order:3}.order-xs-4{order:4}.order-xs-5{order:5}.order-xs-6{order:6}.order-xs-7{order:7}.order-xs-8{order:8}.order-xs-9{order:9}.order-xs-10{order:10}.order-xs-11{order:11}.order-xs-12{order:12}.hidden-xs{display:none}@container praxis-form-row (min-width: 600px){.span-sm-1{grid-column:span 1}.span-sm-2{grid-column:span 2}.span-sm-3{grid-column:span 3}.span-sm-4{grid-column:span 4}.span-sm-5{grid-column:span 5}.span-sm-6{grid-column:span 6}.span-sm-7{grid-column:span 7}.span-sm-8{grid-column:span 8}.span-sm-9{grid-column:span 9}.span-sm-10{grid-column:span 10}.span-sm-11{grid-column:span 11}.span-sm-12{grid-column:span 12}.offset-sm-0{margin-left:0%}.offset-sm-1{margin-left:calc(1 / 12 * 100%)}.offset-sm-2{margin-left:calc(2 / 12 * 100%)}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:calc(4 / 12 * 100%)}.offset-sm-5{margin-left:calc(5 / 12 * 100%)}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:calc(7 / 12 * 100%)}.offset-sm-8{margin-left:calc(8 / 12 * 100%)}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:calc(10 / 12 * 100%)}.offset-sm-11{margin-left:calc(11 / 12 * 100%)}.order-sm--12{order:-12}.order-sm--11{order:-11}.order-sm--10{order:-10}.order-sm--9{order:-9}.order-sm--8{order:-8}.order-sm--7{order:-7}.order-sm--6{order:-6}.order-sm--5{order:-5}.order-sm--4{order:-4}.order-sm--3{order:-3}.order-sm--2{order:-2}.order-sm--1{order:-1}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.hidden-sm{display:none}}@container praxis-form-row (min-width: 900px){.span-md-1{grid-column:span 1}.span-md-2{grid-column:span 2}.span-md-3{grid-column:span 3}.span-md-4{grid-column:span 4}.span-md-5{grid-column:span 5}.span-md-6{grid-column:span 6}.span-md-7{grid-column:span 7}.span-md-8{grid-column:span 8}.span-md-9{grid-column:span 9}.span-md-10{grid-column:span 10}.span-md-11{grid-column:span 11}.span-md-12{grid-column:span 12}.offset-md-0{margin-left:0%}.offset-md-1{margin-left:calc(1 / 12 * 100%)}.offset-md-2{margin-left:calc(2 / 12 * 100%)}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:calc(4 / 12 * 100%)}.offset-md-5{margin-left:calc(5 / 12 * 100%)}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:calc(7 / 12 * 100%)}.offset-md-8{margin-left:calc(8 / 12 * 100%)}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:calc(10 / 12 * 100%)}.offset-md-11{margin-left:calc(11 / 12 * 100%)}.order-md--12{order:-12}.order-md--11{order:-11}.order-md--10{order:-10}.order-md--9{order:-9}.order-md--8{order:-8}.order-md--7{order:-7}.order-md--6{order:-6}.order-md--5{order:-5}.order-md--4{order:-4}.order-md--3{order:-3}.order-md--2{order:-2}.order-md--1{order:-1}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.hidden-md{display:none}}@container praxis-form-row (min-width: 1200px){.span-lg-1{grid-column:span 1}.span-lg-2{grid-column:span 2}.span-lg-3{grid-column:span 3}.span-lg-4{grid-column:span 4}.span-lg-5{grid-column:span 5}.span-lg-6{grid-column:span 6}.span-lg-7{grid-column:span 7}.span-lg-8{grid-column:span 8}.span-lg-9{grid-column:span 9}.span-lg-10{grid-column:span 10}.span-lg-11{grid-column:span 11}.span-lg-12{grid-column:span 12}.offset-lg-0{margin-left:0%}.offset-lg-1{margin-left:calc(1 / 12 * 100%)}.offset-lg-2{margin-left:calc(2 / 12 * 100%)}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:calc(4 / 12 * 100%)}.offset-lg-5{margin-left:calc(5 / 12 * 100%)}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:calc(7 / 12 * 100%)}.offset-lg-8{margin-left:calc(8 / 12 * 100%)}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:calc(10 / 12 * 100%)}.offset-lg-11{margin-left:calc(11 / 12 * 100%)}.order-lg--12{order:-12}.order-lg--11{order:-11}.order-lg--10{order:-10}.order-lg--9{order:-9}.order-lg--8{order:-8}.order-lg--7{order:-7}.order-lg--6{order:-6}.order-lg--5{order:-5}.order-lg--4{order:-4}.order-lg--3{order:-3}.order-lg--2{order:-2}.order-lg--1{order:-1}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.hidden-lg{display:none}}@container praxis-form-row (min-width: 1536px){.span-xl-1{grid-column:span 1}.span-xl-2{grid-column:span 2}.span-xl-3{grid-column:span 3}.span-xl-4{grid-column:span 4}.span-xl-5{grid-column:span 5}.span-xl-6{grid-column:span 6}.span-xl-7{grid-column:span 7}.span-xl-8{grid-column:span 8}.span-xl-9{grid-column:span 9}.span-xl-10{grid-column:span 10}.span-xl-11{grid-column:span 11}.span-xl-12{grid-column:span 12}.offset-xl-0{margin-left:0%}.offset-xl-1{margin-left:calc(1 / 12 * 100%)}.offset-xl-2{margin-left:calc(2 / 12 * 100%)}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:calc(4 / 12 * 100%)}.offset-xl-5{margin-left:calc(5 / 12 * 100%)}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:calc(7 / 12 * 100%)}.offset-xl-8{margin-left:calc(8 / 12 * 100%)}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:calc(10 / 12 * 100%)}.offset-xl-11{margin-left:calc(11 / 12 * 100%)}.order-xl--12{order:-12}.order-xl--11{order:-11}.order-xl--10{order:-10}.order-xl--9{order:-9}.order-xl--8{order:-8}.order-xl--7{order:-7}.order-xl--6{order:-6}.order-xl--5{order:-5}.order-xl--4{order:-4}.order-xl--3{order:-3}.order-xl--2{order:-2}.order-xl--1{order:-1}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.hidden-xl{display:none}}.canvas-mode-enabled{--canvas-hit: 14px}.canvas-mode-enabled .canvas-element{position:relative;z-index:0;border-radius:8px;outline:2px solid transparent;outline-offset:2px;transition:outline-color .2s ease,outline-style .2s ease}.canvas-mode-enabled .canvas-element:before{content:\"\";position:absolute;inset:calc(-1 * var(--canvas-hit));pointer-events:none;border-radius:inherit;background:transparent}.canvas-mode-enabled .canvas-element[data-canvas-type=section]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element[data-canvas-type=row]{--outline-color: var(--md-sys-color-secondary)}.canvas-mode-enabled .canvas-element[data-canvas-type=column],.canvas-mode-enabled .canvas-element[data-canvas-type=field]{--outline-color: var(--md-sys-color-tertiary)}.canvas-mode-enabled .canvas-element[data-canvas-type=actions]{--outline-color: var(--md-sys-color-primary)}.canvas-mode-enabled .canvas-element.hovered:not(.selected){outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:dashed}.canvas-mode-enabled .canvas-element.selected{outline-color:var(--outline-color, var(--md-sys-color-primary));outline-style:solid;box-shadow:0 0 0 2px var(--outline-color, var(--md-sys-color-primary))}.canvas-mode-enabled .canvas-element.hovered{z-index:var(--praxis-layer-authoring-hover, 300)}.canvas-mode-enabled .canvas-element.selected{z-index:var(--praxis-layer-authoring-selected, 320)}.section-drop-wrapper,.row-drop-wrapper,.column-drop-wrapper{display:contents}.add-section-container{display:flex;align-items:center;justify-content:center;padding:.5rem 0;margin:-.5rem 0;position:relative;z-index:var(--praxis-layer-authoring-insert, 280)}.add-section-container .add-section-line{flex-grow:1;height:1px;background:repeating-linear-gradient(90deg,var(--md-sys-color-outline-variant),var(--md-sys-color-outline-variant) 4px,transparent 4px,transparent 8px)}.add-section-container button{margin:0 1rem;transform:scale(.85)}:host{display:block;position:relative;--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--pdx-color-surface, var(--md-sys-color-surface-container)) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent );--pfx-form-shell-padding: clamp(.9rem, 1.4vw, 1.2rem)}.form-config-controls{position:relative;top:auto;margin:0;display:flex;align-items:center;gap:.35rem;z-index:60;background:color-mix(in srgb,var(--pfx-form-shell-surface) 88%,var(--md-sys-color-surface) 12%);padding:8px var(--pfx-form-shell-padding);border:1px solid var(--pfx-form-footer-border);border-bottom-color:color-mix(in srgb,var(--pfx-form-footer-border) 72%,transparent);border-radius:var(--pfx-editorial-form-radius) var(--pfx-editorial-form-radius) 0 0;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);box-shadow:none;min-width:0;justify-content:flex-end;pointer-events:none;opacity:.96;transition:opacity .16s ease,border-color .16s ease}.form-config-controls>*{pointer-events:auto}.form-config-controls:hover,.form-config-controls:focus-within{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant) 74%)}.form-config-controls .praxis-icon-button{color:var(--md-sys-color-on-surface-variant)}.form-config-controls .praxis-icon-button:hover{color:var(--md-sys-color-primary)}.ai-floating-assistant{position:sticky;right:0;bottom:12px;margin-top:14px;margin-left:auto;width:fit-content;z-index:70;pointer-events:none}.ai-floating-assistant button{pointer-events:auto;display:inline-flex}.ai-floating-assistant .ai-trigger-btn{box-shadow:0 12px 28px #0f172a24}.config-button{color:var(--md-sys-color-primary)}.form-loading{display:flex;flex-direction:column;align-items:stretch;justify-content:center;padding:1.25rem;text-align:left;color:var(--md-sys-color-on-surface);gap:1rem;min-height:220px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 14%,var(--md-sys-color-outline-variant) 86%);border-radius:8px;background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary) 8%,transparent),transparent 42%),color-mix(in srgb,var(--md-sys-color-surface-container-low) 78%,var(--md-sys-color-surface) 22%);box-shadow:0 12px 28px #0f172a14}.form-loading-header{display:flex;align-items:center;gap:.85rem}.form-loading-copy{min-width:0}.form-loading p{margin:0}.form-loading-title{font-weight:700;color:var(--md-sys-color-on-surface)}.form-loading-subtitle{margin-top:.2rem;font-size:.875rem;color:var(--md-sys-color-on-surface-variant)}.form-loading-skeleton{display:grid;gap:.7rem}.form-loading-line,.form-loading-field{display:block;overflow:hidden;position:relative;border-radius:6px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 74%,var(--md-sys-color-primary) 6%)}.form-loading-line:after,.form-loading-field:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--md-sys-color-primary) 16%,white 18%),transparent);animation:form-loading-shimmer 1.4s ease-in-out infinite}.form-loading-line{height:12px}.form-loading-line-title{width:min(42%,240px)}.form-loading-line-short{width:min(64%,360px)}.form-loading-field{height:44px}.form-loading-field-wide{height:72px}@keyframes form-loading-shimmer{to{transform:translate(100%)}}@media(prefers-reduced-motion:reduce){.form-loading-line:after,.form-loading-field:after{animation:none;transform:none;opacity:.28}}.form-error{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;text-align:center;color:var(--md-sys-color-error);gap:1rem;border:1px solid var(--md-sys-color-error);border-radius:8px;background-color:var(--md-sys-color-error-container);margin:1rem;box-shadow:0 12px 30px #7f1d1d1f}.form-error h3{margin:0;color:var(--md-sys-color-on-error-container)}.form-error p{margin:0;color:var(--md-sys-color-on-error-container);opacity:.8}.form-error button{margin-top:.5rem}.pfx-form-info-banner{margin-bottom:14px;padding:12px 14px;border-radius:16px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant) 82%);background:color-mix(in srgb,var(--md-sys-color-primary-container) 24%,var(--md-sys-color-surface) 76%);color:var(--md-sys-color-on-surface);display:flex;align-items:flex-start;justify-content:space-between;gap:14px}.pfx-form-info-banner .text{font-size:.92rem;line-height:1.5;font-weight:600}.pfx-form-info-banner .actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px}.praxis-dynamic-form{display:flex;flex-direction:column;max-width:100%;min-width:0;transition:all .3s ease;position:relative;font-family:inherit;font-size:inherit;color:inherit;--pfx-editorial-form-surface: var( --pfx-form-section-surface, var(--md-sys-color-surface-container) );--pfx-editorial-form-surface-muted: var( --pdx-color-surface-muted, var(--md-sys-color-surface-container-low) );--pfx-editorial-form-border: var( --pfx-form-stroke, var(--pdx-color-border-subtle, var(--md-sys-color-outline-variant)) );--pfx-editorial-form-text: var( --pdx-color-text-primary, var(--md-sys-color-on-surface) );--pfx-editorial-form-text-muted: var( --pdx-color-text-secondary, var(--md-sys-color-on-surface-variant) );--pfx-editorial-form-field-surface: color-mix( in srgb, var(--pfx-editorial-form-surface-muted) 76%, var(--pfx-editorial-form-surface) 24% );--pfx-editorial-form-field-outline: color-mix( in srgb, var(--pfx-editorial-form-border) 88%, transparent );--pfx-editorial-form-accent: var( --pdx-color-primary, var(--md-sys-color-primary) );--pfx-editorial-form-accent-text: var(--md-sys-color-on-primary);--pfx-editorial-form-radius: var(--pfx-form-section-radius, 8px);--pfx-editorial-form-field-radius: var(--pfx-form-field-radius, 4px);--pfx-editorial-form-border-width: 1px;--pfx-editorial-form-field-border-width: 1px;--pfx-editorial-form-shadow: none;--pfx-form-shell-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 36%, transparent );--pfx-form-section-surface-flat: color-mix( in srgb, var(--pfx-editorial-form-surface) 78%, var(--pfx-editorial-form-surface-muted) 22% );--pfx-form-section-divider: color-mix( in srgb, var(--pfx-editorial-form-border) 68%, transparent );--pfx-form-label-strong: color-mix( in srgb, var(--pfx-editorial-form-text) 96%, white 4% );--pfx-form-label-muted: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 92%, var(--pfx-editorial-form-text) 8% );--pfx-form-field-surface-rest: color-mix( in srgb, var(--pfx-editorial-form-field-surface) 82%, var(--pfx-editorial-form-surface) 18% );--pfx-form-field-surface-focus: color-mix( in srgb, var(--pfx-editorial-form-accent) 4%, var(--pfx-form-field-surface-rest) 96% );--pfx-form-field-min-height: 48px;--pfx-form-section-padding: clamp(1.1rem, 1.8vw, 1.5rem);--pfx-form-section-gap: 22px;--pdx-presentation-label-size: var(--pfx-pres-compact-label-size, .78rem);--pdx-presentation-value-size: var(--pfx-pres-compact-value-size, 1rem);--pdx-presentation-icon-size: var(--pfx-pres-icon-size, 18px);--pdx-presentation-row-gap: var(--pfx-pres-row-gap, .5rem);--pdx-presentation-column-gap: var(--pfx-pres-column-gap, .5rem);--pdx-presentation-section-gap: var(--pfx-pres-section-gap, .75rem);--pdx-presentation-label-width: var(--pfx-pres-label-width, 220px);--pdx-presentation-flag-height: var(--pfx-pres-boolean-min-height, 22px);--pdx-presentation-flag-radius: var(--pfx-pres-boolean-radius, 999px);--pdx-presentation-flag-padding: var(--pfx-pres-boolean-padding, 0 8px);--pdx-presentation-flag-active-color: var( --pfx-pres-boolean-active-color, var(--md-sys-color-primary) );--pdx-presentation-flag-active-bg: var( --pfx-pres-boolean-active-bg, color-mix(in srgb, var(--md-sys-color-primary) 14%, transparent) );--pdx-presentation-flag-inactive-color: var( --pfx-pres-boolean-inactive-color, var(--md-sys-color-on-surface-variant) );--pdx-presentation-flag-inactive-bg: var( --pfx-pres-boolean-inactive-bg, color-mix(in srgb, var(--md-sys-color-outline-variant) 34%, transparent) );--pfx-form-footer-surface: color-mix( in srgb, var(--pfx-editorial-form-surface) 70%, var(--pfx-editorial-form-surface-muted) 30% );--pfx-form-footer-border: color-mix( in srgb, var(--pfx-editorial-form-border) 76%, transparent )}.praxis-dynamic-form.canvas-mode-enabled{border:1px solid var(--pfx-form-footer-border);border-radius:var(--pfx-editorial-form-radius);background:linear-gradient(180deg,color-mix(in srgb,var(--pfx-form-shell-surface) 86%,transparent),color-mix(in srgb,var(--pfx-editorial-form-surface-muted) 42%,transparent));overflow:visible}.form-config-controls+.praxis-dynamic-form.canvas-mode-enabled{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks{margin-inline:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>.section-drop-wrapper:first-of-type,.praxis-dynamic-form.canvas-mode-enabled>.form-editorial-blocks:first-child{margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.canvas-mode-enabled>praxis-form-actions[data-actions-placement=afterSections]{display:block;margin-top:var(--pfx-form-shell-padding)}.praxis-dynamic-form.editorial-visual-context{--_pfx-editorial-host-text: var( --editorial-text-primary, var(--foreground, var(--mat-sys-on-surface, #1d1b20)) );--_pfx-editorial-host-text-muted: var( --editorial-text-secondary, var( --muted-foreground, color-mix(in srgb, var(--_pfx-editorial-host-text) 64%, transparent) ) );--_pfx-editorial-host-surface: var( --editorial-surface-primary, var(--card, var(--mat-sys-surface-container, #ffffff)) );--_pfx-editorial-host-surface-muted: var( --editorial-surface-secondary, var(--surface-dim, var(--muted, var(--mat-sys-surface-container-low, #f7f2fa))) );--_pfx-editorial-host-border: var( --editorial-border-color, var(--border, var(--mat-sys-outline-variant, #cac4d0)) );--_pfx-editorial-host-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--primary, var(--mat-sys-primary, #6750a4))) );--_pfx-editorial-host-accent-text: var( --editorial-cta-primary-text, var( --editorial-accent-contrast, var(--primary-foreground, var(--mat-sys-on-primary, #ffffff)) ) );--_pfx-editorial-host-accent-container: var( --primary-container, color-mix(in srgb, var(--_pfx-editorial-host-accent) 16%, var(--_pfx-editorial-host-surface) 84%) );--_pfx-editorial-host-accent-container-text: var( --primary-container-fg, var(--_pfx-editorial-host-accent) );font-family:var(--editorial-body-font-family, inherit);font-size:var(--editorial-body-size, 1rem);color:var(--_pfx-editorial-host-text);--pfx-editorial-form-surface: var( --editorial-surface-primary, var(--pfx-form-section-surface, var(--_pfx-editorial-host-surface)) );--pfx-editorial-form-surface-muted: var( --editorial-surface-secondary, var(--_pfx-editorial-host-surface-muted) );--pfx-editorial-form-border: var( --editorial-border-color, var(--pfx-form-stroke, var(--_pfx-editorial-host-border)) );--pfx-editorial-form-text: var( --editorial-text-primary, var(--_pfx-editorial-host-text) );--pfx-editorial-form-text-muted: var( --editorial-text-secondary, color-mix( in srgb, var(--_pfx-editorial-host-text-muted) 86%, var(--_pfx-editorial-host-text) 14% ) );--pfx-editorial-form-accent: var( --editorial-cta-primary, var(--editorial-accent, var(--_pfx-editorial-host-accent)) );--pfx-editorial-form-accent-text: var( --editorial-cta-primary-text, var(--editorial-accent-contrast, var(--_pfx-editorial-host-accent-text)) );--pfx-editorial-form-accent-container: var(--_pfx-editorial-host-accent-container);--pfx-editorial-form-accent-container-text: var(--_pfx-editorial-host-accent-container-text);--pfx-editorial-form-radius: var(--editorial-card-radius, 18px);--pfx-editorial-form-field-radius: var( --editorial-field-radius, var(--editorial-card-radius, 14px) );--pfx-editorial-form-border-width: var(--editorial-card-border-width, 1px);--pfx-editorial-form-field-border-width: var(--editorial-field-border-width, 1px);--pfx-editorial-form-shadow: var(--editorial-card-shadow, none);--md-sys-color-surface: var( --pfx-editorial-form-surface, var(--md-sys-color-surface) );--md-sys-color-surface-container: var( --pfx-editorial-form-surface, var(--md-sys-color-surface-container) );--md-sys-color-surface-container-low: var( --pfx-editorial-form-surface-muted, var(--md-sys-color-surface-container-low) );--md-sys-color-surface-variant: var( --pfx-editorial-form-field-surface, var(--md-sys-color-surface-variant) );--md-sys-color-outline: var( --pfx-editorial-form-field-outline, var(--md-sys-color-outline) );--md-sys-color-outline-variant: var( --pfx-editorial-form-border, var(--md-sys-color-outline-variant) );--md-sys-color-on-surface: var( --editorial-text-primary, inherit );--md-sys-color-on-surface-variant: var( --editorial-text-secondary, inherit );--md-sys-color-primary: var( --pfx-editorial-form-accent, var(--md-sys-color-primary) );--md-sys-color-primary-container: var( --pfx-editorial-form-accent-container, var(--md-sys-color-primary-container) );--md-sys-color-on-primary-container: var( --pfx-editorial-form-accent-container-text, var(--md-sys-color-on-primary-container) );--md-sys-color-on-primary: var( --pfx-editorial-form-accent-text, var(--md-sys-color-on-primary) );--md-sys-color-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );--mat-sys-on-surface: var( --editorial-text-primary, inherit );--mat-sys-on-surface-variant: var( --editorial-text-secondary, inherit );--mat-sys-on-surface-rgb: var( --editorial-text-primary-rgb, inherit );color:inherit;color-scheme:light}.praxis-dynamic-form.presentation-mode .form-row,.praxis-dynamic-form.readonly-mode .form-row{gap:var(--pdx-presentation-column-gap);margin-bottom:var(--pdx-presentation-row-gap)}.praxis-dynamic-form.presentation-mode{--pfx-pres-on-surface: var( --pdx-color-text-primary, var(--pfx-editorial-form-text, var(--pfx-form-label-strong, currentColor)) );--pfx-pres-on-surface-variant: var( --pdx-color-text-secondary, var( --pfx-editorial-form-text-muted, var( --pfx-form-label-muted, color-mix(in srgb, var(--pfx-pres-on-surface) 78%, transparent) ) ) )}.praxis-dynamic-form.presentation-mode .form-section,.praxis-dynamic-form.readonly-mode .form-section{padding:var(--pdx-presentation-section-gap) .875rem}.praxis-dynamic-form.pres-compact .form-row{gap:var(--pdx-presentation-column-gap, .35rem);margin-bottom:var(--pdx-presentation-row-gap, .35rem)}.praxis-dynamic-form.pres-compact .form-section{padding:var(--pdx-presentation-section-gap, .5rem) .75rem}.praxis-dynamic-form.pres-label-left .praxis-presentation{display:grid;grid-template-columns:minmax(0,var(--pfx-presentation-label-w, var(--pdx-presentation-label-width))) minmax(0,1fr);align-items:baseline;column-gap:var(--pdx-presentation-column-gap, 10px)}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:right;margin-bottom:0}@media(max-width:480px){.praxis-dynamic-form.pres-label-left .praxis-presentation{grid-template-columns:minmax(0,1fr);row-gap:4px}.praxis-dynamic-form.pres-label-left .praxis-presentation__label{text-align:start}}.form-section{border:1px solid var(--pfx-form-section-divider);border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);max-width:100%;min-width:0;background:var(--pfx-form-section-surface-flat);box-shadow:none;transition:all .2s ease;position:relative}.praxis-dynamic-form.editorial-visual-context .form-section:not(.section-appearance-plain){border:var(--pfx-editorial-form-border-width) solid var(--pfx-editorial-form-border)!important;background:var(--pfx-editorial-form-surface)!important;color:var(--pfx-editorial-form-text);box-shadow:var(--editorial-card-shadow, none)}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{background-color:var(--pfx-editorial-form-surface)!important;background-image:linear-gradient(180deg,color-mix(in srgb,var(--editorial-accent, var(--md-sys-color-primary)) 6%,transparent) 0%,transparent 132px)!important;background-repeat:no-repeat!important}.section-drop-wrapper>.form-section{margin-bottom:var(--pfx-section-gap, 20px)}.section-drop-wrapper:last-of-type>.form-section{margin-bottom:0}.praxis-dynamic-form>praxis-form-actions[data-actions-placement=afterSections]{margin-top:var(--pfx-actions-gap-top, var(--pfx-section-gap, 20px))}.section-title{margin:0 0 var(--pfx-section-title-mb, 12px) 0;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-size:var(--editorial-step-title-size, 1.12rem);font-weight:700;color:var(--pfx-form-label-strong)}.section-heading{position:relative;display:flex;align-items:flex-start;gap:12px;margin-bottom:18px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 18px)}.section-heading:after{content:\"\";position:absolute;right:0;bottom:0;left:0;height:2px;pointer-events:none;background:linear-gradient(90deg,transparent 0%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 8%,var(--pfx-form-section-divider) 46%,var(--pfx-form-section-divider) 54%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 92%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%);mask-image:linear-gradient(90deg,transparent 0%,black 18%,black 82%,transparent 100%)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 10px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:none}.section-heading.align-center{flex-direction:column;align-items:center;text-align:center}.section-heading.align-center .section-heading-text{display:grid;justify-items:center}.section-step-label{display:inline-flex;align-items:center;min-height:24px;padding:0 10px;margin:0 0 8px;border-radius:999px;background:color-mix(in srgb,var(--pfx-editorial-form-accent) 10%,transparent);color:color-mix(in srgb,var(--pfx-editorial-form-accent) 84%,var(--pfx-form-label-strong) 16%);font-size:.72rem;font-weight:800;font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));letter-spacing:.08em;text-transform:uppercase}.section-heading-text{flex:1 1 auto;min-width:0}.section-heading-actions{display:inline-flex;align-items:center;align-self:flex-start;flex-wrap:wrap;gap:4px;margin-left:auto}.section-heading-actions.align-center{align-self:center;margin-left:0}.section-heading-action-btn{color:var(--pfx-form-label-muted)}.section-heading-action-btn.tone-primary{color:var(--md-sys-color-primary)}.section-heading-action-btn.tone-accent,.section-heading-action-btn.tone-secondary{color:var(--md-sys-color-tertiary)}.section-heading-action-btn.tone-warn,.section-heading-action-btn.tone-danger,.section-heading-action-btn.tone-error{color:var(--md-sys-color-error)}.section-heading-action-btn .mat-mdc-progress-spinner,.section-heading-action-btn mat-progress-spinner{--mdc-circular-progress-active-indicator-color: currentColor}.section-heading-action-btn.loading{opacity:.72;pointer-events:none}.section-heading-action-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.section-collapse-btn{margin-left:4px;color:var(--pfx-form-label-muted)}.section-title.title-large{font:var(--mdc-typography-title-large, 500 22px/28px system-ui)}.section-title.title-medium{font:var(--mdc-typography-title-medium, 500 16px/24px system-ui)}.section-title.title-small{font:var(--mdc-typography-title-small, 500 14px/20px system-ui)}.section-title.headline-small{font:var(--mdc-typography-headline-small, 600 24px/32px system-ui)}.section-title.title-large,.section-title.title-medium,.section-title.title-small,.section-title.headline-small{font-family:var(--editorial-title-font-family, var(--editorial-body-font-family, inherit));font-weight:var(--editorial-title-weight, 600)}.section-description{margin:0;font-family:var(--editorial-body-font-family, inherit);font-size:.93rem;color:var(--pfx-form-label-muted);line-height:1.6}.section-description.body-large{font:var(--mdc-typography-body-large, 400 16px/24px system-ui)}.section-description.body-medium{font:var(--mdc-typography-body-medium, 400 14px/20px system-ui)}.section-description.body-small{font:var(--mdc-typography-body-small, 400 12px/16px system-ui)}.section-description.body-large,.section-description.body-medium,.section-description.body-small{font-family:var(--editorial-body-font-family, inherit);font-weight:var(--editorial-body-weight, 400)}.section-title.align-center,.section-description.align-center,.section-step-label.align-center{text-align:center}.praxis-dynamic-form .form-section.section-appearance-plain{border-color:transparent;border-radius:0;padding:0;background:transparent}.form-section.section-appearance-plain .section-heading{margin-bottom:14px}.form-section.section-appearance-step{border-radius:var(--pfx-editorial-form-radius);padding:var(--pfx-form-section-padding);background:var(--pfx-form-section-surface-flat);border-color:var(--pfx-form-section-divider);box-shadow:none}.praxis-dynamic-form.editorial-visual-context .form-section.section-appearance-step{border-radius:var(--editorial-card-radius, 20px);box-shadow:none}.form-section.section-appearance-step .section-heading{margin-bottom:22px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 16px)}.form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 16px)}:host(.pfx-form-section-divider-inline-title) .form-section.section-appearance-step .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-inline-divider-gap, 0)}.form-section.section-appearance-step .section-title{font:var(--mdc-typography-title-large, 700 22px/28px system-ui);color:var(--pfx-form-label-strong);margin-bottom:8px}.form-section.section-appearance-step .section-description{color:var(--pfx-form-label-muted);max-width:60ch}.form-section.section-appearance-step .section-step-label{min-height:24px;padding:0 10px;margin-bottom:10px;box-shadow:none}.form-section.section-appearance-step .section-heading.align-center .section-description{max-width:52ch}.form-section.section-appearance-step .section-body{display:grid;gap:8px;padding-top:0}.form-section.section-appearance-step .form-row{margin-bottom:var(--pfx-field-gap, 1rem)}.form-section.section-appearance-step .form-column{gap:var(--pfx-field-gap, 12px)}.form-section .form-editorial-blocks{display:grid;gap:16px}.form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{margin-top:24px;padding-top:18px;border-top:1px solid var(--pfx-form-section-divider)}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]{gap:18px}.form-section.section-appearance-step .form-editorial-blocks[data-editorial-placement=beforeActions]>*+*{margin-top:2px}.praxis-dynamic-form:not(.canvas-mode-enabled)>praxis-form-actions[data-actions-placement=afterSections]{margin-top:18px}.praxis-dynamic-form>.form-editorial-blocks[data-editorial-placement=after]{margin-top:6px}:host-context(.mdc-theme-dark) .form-section.section-appearance-step,:host-context(.theme-dark) .form-section.section-appearance-step{border-color:color-mix(in srgb,var(--pfx-editorial-form-border) 82%,transparent);box-shadow:none}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-title,:host-context(.theme-dark) .form-section.section-appearance-step .section-title{color:color-mix(in srgb,var(--pfx-editorial-form-text) 96%,white)}:host-context(.mdc-theme-dark) .form-section.section-appearance-step .section-description,:host-context(.theme-dark) .form-section.section-appearance-step .section-description{color:color-mix(in srgb,var(--pfx-editorial-form-text-muted) 86%,var(--pfx-editorial-form-text) 14%)}:host-context(.mdc-theme-dark) .section-step-label,:host-context(.theme-dark) .section-step-label{background:color-mix(in srgb,var(--md-sys-color-primary-container) 54%,transparent);color:color-mix(in srgb,var(--md-sys-color-primary) 88%,white)}:host-context(.mdc-theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions],:host-context(.theme-dark) .form-section .form-editorial-blocks[data-editorial-placement=beforeActions]{border-top-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 90%,transparent)}.inline-edit-btn{margin-left:6px;vertical-align:middle}.section-body.collapsed{border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low);border-radius:6px;padding:8px 10px}.section-collapsed-placeholder{display:flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:.95rem}.section-collapsed-placeholder mat-icon{font-size:20px;width:20px;height:20px}.form-row{display:flex;gap:1.1rem;margin-bottom:var(--pfx-field-gap, 1.1rem);max-width:100%;min-width:0;transition:all .2s ease;border-radius:6px;position:relative}.praxis-dynamic-form.pfx-mounting .form-row{opacity:0;transform:translateY(var(--pdx-form-mount-offset, 6px));animation:pdxFormMount var(--pdx-form-mount-duration, .16s) ease-out both;animation-delay:calc(var(--pfx-mount-index, 0) * var(--pdx-form-mount-stagger, 20ms))}@media(prefers-reduced-motion:reduce){.praxis-dynamic-form.pfx-mounting .form-row{animation:none;opacity:1;transform:none}}@keyframes pdxFormMount{to{opacity:1;transform:translateY(0)}}.praxis-dynamic-form .mat-mdc-form-field{width:100%;margin-bottom:var(--pfx-field-gap, 10px);font-family:inherit;--mdc-filled-text-field-container-color: var(--pfx-form-field-surface-rest);--mdc-filled-text-field-focus-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-active-indicator-color: var(--pfx-editorial-form-field-outline);--mdc-filled-text-field-hover-active-indicator-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-filled-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-caret-color: var(--pfx-editorial-form-accent);--mdc-filled-text-field-input-text-placeholder-color: color-mix( in srgb, var(--pfx-editorial-form-text-muted) 82%, transparent );--mdc-outlined-text-field-outline-color: var(--pfx-editorial-form-field-outline);--mdc-outlined-text-field-hover-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-outline-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-focus-label-text-color: var(--pfx-editorial-form-accent);--mdc-outlined-text-field-label-text-color: var(--pfx-form-label-muted);--mdc-outlined-text-field-input-text-color: var(--pfx-editorial-form-text);--mdc-filled-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-outlined-text-field-container-shape: var(--pfx-editorial-form-field-radius);--mdc-filled-text-field-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-filled-text-field-focus-active-indicator-height: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-outline-width: var(--pfx-editorial-form-field-border-width);--mdc-outlined-text-field-focus-outline-width: var(--pfx-editorial-form-field-border-width);--mat-select-enabled-trigger-text-color: var(--pfx-editorial-form-text);--mat-select-enabled-arrow-color: var(--pfx-form-label-muted);--mat-form-field-enabled-select-arrow-color: var(--pfx-form-label-muted);--mat-form-field-focus-select-arrow-color: var(--pfx-editorial-form-accent);--mat-form-field-hover-state-layer-opacity: 0;--mat-form-field-focus-state-layer-opacity: 0}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field{font-family:var(--editorial-body-font-family, inherit)}.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{background:var(--pfx-form-field-surface-rest);border-radius:var(--pfx-editorial-form-field-radius);min-height:var(--pfx-form-field-min-height);transition:background-color .16s ease,box-shadow .16s ease,border-color .16s ease}.praxis-dynamic-form.editorial-visual-context .mat-mdc-text-field-wrapper,.praxis-dynamic-form.editorial-visual-context .mdc-text-field,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--filled,.praxis-dynamic-form.editorial-visual-context .mdc-text-field--outlined{background-color:var(--pfx-form-field-surface-rest)!important;background:var(--pfx-form-field-surface-rest)!important}.praxis-dynamic-form .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-form-label-muted)}.praxis-dynamic-form .mat-mdc-input-element,.praxis-dynamic-form .mat-mdc-select-value-text,.praxis-dynamic-form .mat-mdc-form-field-infix,.praxis-dynamic-form .mat-mdc-select-min-line{color:var(--pfx-editorial-form-text)}.praxis-dynamic-form .mat-mdc-form-field:hover .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field:hover .mdc-text-field,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mat-mdc-form-field.mat-focused .mdc-text-field{background:var(--pfx-form-field-surface-focus)}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-value-text,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field-infix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-select-min-line,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input{color:var(--pfx-editorial-form-text)!important;-webkit-text-fill-color:var(--pfx-editorial-form-text)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-hint,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-error,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-required-marker,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-arrow,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-select-placeholder,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-suffix,.praxis-dynamic-form.editorial-visual-context .mat-mdc-form-field .mat-mdc-form-field-icon-prefix{color:var(--pfx-editorial-form-text-muted)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-floating-label,.praxis-dynamic-form.editorial-visual-context .mdc-text-field__input::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 68%,transparent)!important}.praxis-dynamic-form.editorial-visual-context .mat-mdc-input-element::placeholder,.praxis-dynamic-form.editorial-visual-context textarea.mat-mdc-input-element::placeholder{color:color-mix(in srgb,var(--pfx-editorial-form-text) 58%,transparent)!important}.praxis-dynamic-form .mat-mdc-radio-button,.praxis-dynamic-form .mat-mdc-checkbox,.praxis-dynamic-form .mat-mdc-slide-toggle{--mdc-radio-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-radio-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-checkmark-color: var(--pfx-editorial-form-accent-text);--mdc-checkbox-selected-focus-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-hover-icon-color: var(--pfx-editorial-form-accent);--mdc-checkbox-selected-icon-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-focus-state-layer-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-handle-color: var(--pfx-editorial-form-accent);--mdc-switch-selected-track-color: color-mix(in srgb, var(--pfx-editorial-form-accent) 45%, #fff)}.praxis-dynamic-form [data-field-type=input],.praxis-dynamic-form [data-field-type=textarea],.praxis-dynamic-form [data-field-type=email],.praxis-dynamic-form [data-field-type=password],.praxis-dynamic-form [data-field-type=url],.praxis-dynamic-form [data-field-type=search],.praxis-dynamic-form [data-field-type=phone],.praxis-dynamic-form [data-field-type=numericTextBox],.praxis-dynamic-form [data-field-type=currency],.praxis-dynamic-form [data-field-type=cpfCnpj],.praxis-dynamic-form [data-field-type=date],.praxis-dynamic-form [data-field-type=dateInput],.praxis-dynamic-form [data-field-type=dateRange],.praxis-dynamic-form [data-field-type=dateTimeLocal],.praxis-dynamic-form [data-field-type=time],.praxis-dynamic-form [data-field-type=timePicker],.praxis-dynamic-form [data-field-type=timeRange],.praxis-dynamic-form [data-field-type=month],.praxis-dynamic-form [data-field-type=week],.praxis-dynamic-form [data-field-type=yearInput],.praxis-dynamic-form [data-field-type=select],.praxis-dynamic-form [data-field-type=multi-select],.praxis-dynamic-form [data-field-type=searchable-select],.praxis-dynamic-form [data-field-type=async-select],.praxis-dynamic-form [data-field-type=autocomplete],.praxis-dynamic-form [data-field-type=entityLookup],.praxis-dynamic-form [data-field-type=tree-select],.praxis-dynamic-form [data-field-type=multi-select-tree],.praxis-dynamic-form [data-field-type=priceRange],.praxis-dynamic-form [data-field-type=file-upload]{display:block;width:100%;min-width:0}.praxis-dynamic-form .mat-mdc-form-field-subscript-wrapper{min-height:var(--pfx-subscript-min-h, 22px)}.form-row:last-child{margin-bottom:0}.form-column{display:grid;grid-template-columns:minmax(0,1fr);align-content:start;gap:var(--pfx-field-gap, 10px);flex:1;max-width:100%;min-width:0;transition:all .2s ease;border-radius:4px;position:relative}.form-layout-rich-content{display:block;width:100%;max-width:100%;min-width:0;margin-bottom:var(--pfx-field-gap, 10px);color:var(--pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant));font:var(--mdc-typography-body-medium, 400 14px/20px system-ui);overflow-wrap:anywhere}:host ::ng-deep .form-layout-rich-content .prx-rich-content-root{display:grid;gap:8px;min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-node{min-width:0;max-width:100%}:host ::ng-deep .form-layout-rich-content .prx-rich-text{color:inherit;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{border:1px solid color-mix(in srgb,var(--pfx-editorial-form-accent) 12%,var(--pfx-editorial-form-border) 88%);border-left:3px solid var(--pfx-editorial-form-accent);border-radius:8px;background:color-mix(in srgb,var(--pfx-editorial-form-accent-container) 12%,var(--pfx-editorial-form-surface-muted) 88%)}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note{display:grid;grid-template-columns:20px minmax(0,1fr);gap:10px;align-items:flex-start;padding:11px 12px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note:before{content:\"info\";display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;color:var(--pfx-editorial-form-accent);font-family:Material Symbols Outlined;font-size:20px;font-weight:400;line-height:20px}:host ::ng-deep .form-layout-rich-content .praxis-form-visual-block--note .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice{padding:10px 12px;color:var(--pfx-editorial-form-text)}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-compose{align-items:flex-start;gap:10px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-notice .prx-rich-icon{color:var(--pfx-editorial-form-accent);font-size:20px;line-height:20px;margin-top:1px}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider{display:grid;grid-template-columns:minmax(24px,1fr) auto minmax(24px,1fr);align-items:center;gap:10px;color:var(--pfx-editorial-form-text-muted);font:var(--mdc-typography-label-small, 600 12px/16px system-ui);text-transform:uppercase}:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:before,:host ::ng-deep .form-layout-rich-content .praxis-rich-content-divider:after{content:\"\";height:1px;background:var(--pfx-editorial-form-border)}:host ::ng-deep .form-layout-rich-content .prx-rich-card{gap:6px;padding:12px 14px;border-color:var(--pfx-editorial-form-border);border-radius:8px;background:var(--pfx-editorial-form-surface-muted);color:var(--pfx-editorial-form-text);box-shadow:none}:host ::ng-deep .form-layout-rich-content .prx-rich-card-title{color:var(--pfx-editorial-form-text);font:var(--mdc-typography-title-small, 600 14px/20px system-ui)}:host ::ng-deep .form-layout-rich-content .prx-rich-card-subtitle,:host ::ng-deep .form-layout-rich-content .prx-rich-metric-caption{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-card .prx-rich-text{color:var(--pfx-editorial-form-text-muted)}:host ::ng-deep .form-layout-rich-content .prx-rich-badge{background:var(--pfx-editorial-form-accent-container);color:var(--pfx-editorial-form-accent-container-text)}.form-row.grid-12{container-type:inline-size;container-name:praxis-form-row;display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pfx-grid-gap, 16px)}.align-start{align-self:flex-start}.align-center{align-self:center}.align-end{align-self:flex-end}.align-stretch{align-self:stretch}.form-blocking-overlay{position:absolute;inset:0;background:transparent;color:var(--md-sys-color-on-surface);backdrop-filter:blur(2px) saturate(103%);-webkit-backdrop-filter:blur(2px) saturate(103%);display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;z-index:10;pointer-events:all}@media(max-width:768px){.column-drop-wrapper,.row-drop-wrapper,.form-layout-rich-content,.praxis-dynamic-form .mat-mdc-form-field,.praxis-dynamic-form .mat-mdc-text-field-wrapper,.praxis-dynamic-form .mdc-text-field{max-width:100%;min-width:0}:host ::ng-deep .praxis-dynamic-form .pfx-field-shell,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-wrapper,:host ::ng-deep .praxis-dynamic-form .pfx-field-shell-host,:host ::ng-deep .praxis-dynamic-form .mat-mdc-form-field,:host ::ng-deep .praxis-dynamic-form .mat-mdc-text-field-wrapper,:host ::ng-deep .praxis-dynamic-form .mdc-text-field{width:100%;max-width:100%;min-width:0}.form-section{padding:clamp(.75rem,4vw,1rem)}.section-heading{gap:10px;margin-bottom:16px;padding-bottom:var(--pfx-form-section-heading-divider-gap, 14px)}.section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}}.section-title{display:flex;align-items:center;gap:8px}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:100%;min-width:0}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{content:\"\";display:block;flex:1 1 auto;min-width:var(--pfx-form-section-title-inline-divider-min-width, 48px);height:2px;margin-left:var(--pfx-form-section-title-inline-divider-gap, 12px);pointer-events:none;background:linear-gradient(90deg,var(--pfx-form-section-divider) 0%,var(--pfx-form-section-divider) 62%,color-mix(in srgb,var(--pfx-form-section-divider) 18%,transparent) 88%,transparent 100%);border-radius:999px;-webkit-mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%);mask-image:linear-gradient(90deg,black 0%,black 72%,transparent 100%)}:host(.pfx-form-section-divider-inline-title) .section-heading.align-center .section-title:after{display:none}@media(max-width:640px){:host(.pfx-form-section-divider-inline-title) .section-heading.title-only{padding-bottom:var(--pfx-form-section-heading-title-only-divider-gap, 8px)}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only:after{display:block}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title{width:auto}:host(.pfx-form-section-divider-inline-title) .section-heading.title-only .section-title:after{display:none}}.section-title .section-title-icon{font-size:1.25em;line-height:1}.section-title-avatar{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px));display:inline-flex;align-items:center;justify-content:center;width:var(--_pfx-form-section-avatar-size);height:var(--_pfx-form-section-avatar-size);border-radius:999px;flex:0 0 var(--_pfx-form-section-avatar-size);overflow:hidden}.section-title-avatar.size-sm{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-sm, 24px)}.section-title-avatar.size-md{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-md, var(--pfx-form-section-avatar-size, 32px))}.section-title-avatar.size-lg{--_pfx-form-section-avatar-size: var(--pfx-form-section-avatar-size-lg, 40px)}.section-title-avatar-image{object-fit:cover;border:1px solid color-mix(in srgb,var(--pfx-form-section-divider) 72%,transparent);background:var(--pfx-form-section-surface-flat)}.section-title-avatar-text,.section-title-avatar-placeholder{background:color-mix(in srgb,var(--pfx-editorial-form-accent) 14%,var(--pfx-form-section-surface-flat));color:color-mix(in srgb,var(--pfx-editorial-form-accent) 82%,var(--pfx-form-label-strong) 18%);font-size:calc(var(--_pfx-form-section-avatar-size) * .41);font-weight:800;letter-spacing:.04em;text-transform:uppercase}.section-title-avatar-placeholder mat-icon{font-size:calc(var(--_pfx-form-section-avatar-size) * .5625);width:calc(var(--_pfx-form-section-avatar-size) * .5625);height:calc(var(--_pfx-form-section-avatar-size) * .5625);line-height:calc(var(--_pfx-form-section-avatar-size) * .5625)}.section-title-avatar-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.form-context-empty-state{display:grid;min-height:var(--pdx-form-context-empty-min-height, clamp(9.25rem, 20vh, 14rem));place-items:center;padding:var(--pdx-form-context-empty-padding, clamp(1.5rem, 3vw, 2.5rem))}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}\n"] }]
20512
20591
  }], ctorParameters: () => [{ type: i1.GenericCrudService }, { type: i2.HttpClient }, { type: i1$3.FormBuilder }, { type: i0.ChangeDetectorRef }, { type: FormLayoutService }, { type: FormContextService }, { type: FormRulesService }, { type: i7.SettingsPanelService }, { type: i2$1.MatDialog }, { type: undefined, decorators: [{
20513
20592
  type: Inject,
20514
20593
  args: [ASYNC_CONFIG_STORAGE]
@@ -20618,6 +20697,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20618
20697
  type: Input
20619
20698
  }], presentationModeGlobal: [{
20620
20699
  type: Input
20700
+ }], presentation: [{
20701
+ type: Input
20621
20702
  }], visibleGlobal: [{
20622
20703
  type: Input
20623
20704
  }], fieldIconPolicy: [{
@@ -29752,7 +29833,33 @@ class PraxisDynamicFormConfigEditor {
29752
29833
  includeBindingsBlock = false;
29753
29834
  editorMode;
29754
29835
  // Indica se o editor foi aberto com o formulário em modo apresentação
29755
- isPresentationMode = false;
29836
+ get isPresentationMode() { return this.supportsPresentationSettings; }
29837
+ // Filter Form shares the document editor but has no presentation runtime.
29838
+ supportsPresentationSettings = true;
29839
+ inputPresentationMode;
29840
+ get displayMode() {
29841
+ return this.inputPresentationMode === true ? 'presentation'
29842
+ : this.inputPresentationMode === false ? 'fields' : 'automatic';
29843
+ }
29844
+ onDisplayModeChange(value) {
29845
+ this.inputPresentationMode = value === 'automatic' ? null : value === 'presentation';
29846
+ this.updateDirtyState('display-mode-change');
29847
+ }
29848
+ get displayModeHint() {
29849
+ if (this.inputMode !== 'view')
29850
+ return this.inputPresentationMode === true
29851
+ ? 'config.general.displayMode.pendingHint' : 'config.general.displayMode.entryHint';
29852
+ return this.inputPresentationMode === true ? 'config.general.displayMode.viewHint'
29853
+ : this.inputPresentationMode === false ? 'config.general.displayMode.readonlyHint'
29854
+ : 'config.general.displayMode.automaticHint';
29855
+ }
29856
+ useViewMode() {
29857
+ this.inputMode = 'view';
29858
+ this.onInputModeChange();
29859
+ }
29860
+ openPresentationStyle() {
29861
+ this.selectedConfigTabIndex = this.getConfigTabIndex('presentation');
29862
+ }
29756
29863
  truncatePreview = false;
29757
29864
  previewItems = [];
29758
29865
  // Presentation preferences (persisted outside FormConfig)
@@ -29915,7 +30022,7 @@ class PraxisDynamicFormConfigEditor {
29915
30022
  this.inputMode = this.normalizeMode(initialDocument.bindings?.mode);
29916
30023
  this.editorMode = this.inputMode;
29917
30024
  // Flag de contexto do host (praxis-dynamic-form)
29918
- this.isPresentationMode = !!data?.presentationMode;
30025
+ this.inputPresentationMode = initialDocument.bindings?.presentationModeGlobal;
29919
30026
  this.initialConfig = this.stripLegacy(normalizeFormConfig(formCfg));
29920
30027
  try {
29921
30028
  this.debugLog('[FormConfigEditor] ctor: initial', {
@@ -29958,6 +30065,7 @@ class PraxisDynamicFormConfigEditor {
29958
30065
  this.backConfig = this.createBackConfigState(this.initialDocument.contextSnapshot?.backConfig);
29959
30066
  this.includeBindingsBlock = Object.prototype.hasOwnProperty.call(this.initialDocument.bindings || {}, 'mode');
29960
30067
  this.inputMode = this.normalizeMode(this.initialDocument.bindings?.mode);
30068
+ this.inputPresentationMode = this.initialDocument.bindings?.presentationModeGlobal;
29961
30069
  this.includePresentationBlock = Object.prototype.hasOwnProperty.call(this.initialDocument.contextSnapshot || {}, 'presentation');
29962
30070
  this.presentationPrefs = this.mergePresentationPrefs(this.initialDocument.contextSnapshot?.presentation);
29963
30071
  this.includeSchemaPrefsBlock = Object.prototype.hasOwnProperty.call(this.initialDocument.contextSnapshot || {}, 'schemaPrefs');
@@ -30050,6 +30158,7 @@ class PraxisDynamicFormConfigEditor {
30050
30158
  ? Object.prototype.hasOwnProperty.call(document.bindings || {}, 'mode')
30051
30159
  : this.includeBindingsBlock || !!document.bindings?.mode;
30052
30160
  this.inputMode = this.normalizeMode(document.bindings?.mode);
30161
+ this.inputPresentationMode = document.bindings?.presentationModeGlobal;
30053
30162
  this.includePresentationBlock = isCanonicalDocument
30054
30163
  ? Object.prototype.hasOwnProperty.call(document.contextSnapshot || {}, 'presentation')
30055
30164
  : this.includePresentationBlock || !!document.contextSnapshot?.presentation;
@@ -30846,7 +30955,7 @@ class PraxisDynamicFormConfigEditor {
30846
30955
  this.updateDirtyState('back-config-change');
30847
30956
  }
30848
30957
  isBindingsBlockPersisted() {
30849
- return this.includeBindingsBlock;
30958
+ return this.includeBindingsBlock || this.inputPresentationMode !== undefined;
30850
30959
  }
30851
30960
  isPresentationBlockPersisted() {
30852
30961
  return this.includePresentationBlock;
@@ -31398,11 +31507,10 @@ class PraxisDynamicFormConfigEditor {
31398
31507
  });
31399
31508
  return createDynamicFormAuthoringDocument({
31400
31509
  config: this.stripLegacy(this.editedConfig),
31401
- bindings: this.includeBindingsBlock
31402
- ? {
31403
- mode: this.inputMode,
31404
- }
31405
- : undefined,
31510
+ bindings: {
31511
+ mode: this.includeBindingsBlock ? this.inputMode : undefined,
31512
+ presentationModeGlobal: this.inputPresentationMode,
31513
+ },
31406
31514
  contextSnapshot,
31407
31515
  });
31408
31516
  }
@@ -31473,7 +31581,7 @@ class PraxisDynamicFormConfigEditor {
31473
31581
  toBackConfigSnapshot() {
31474
31582
  return structuredClone(this.backConfig || { returnTo: '', confirmOnDirty: true });
31475
31583
  }
31476
- tx(key, fallback, params) {
31584
+ tx(key, fallback = key, params) {
31477
31585
  return this.i18n?.t(key, params, fallback, PRAXIS_DYNAMIC_FORM_I18N_NAMESPACE) ?? this.interpolateFallback(fallback, params);
31478
31586
  }
31479
31587
  resolveI18n() {
@@ -31491,7 +31599,7 @@ class PraxisDynamicFormConfigEditor {
31491
31599
  return Object.entries(params).reduce((text, [key, value]) => text.split(`{{${key}}}`).join(String(value)), fallback);
31492
31600
  }
31493
31601
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicFormConfigEditor, deps: [{ token: ASYNC_CONFIG_STORAGE }, { token: FormConfigService }, { token: i7.SettingsPanelService }, { token: i0.ChangeDetectorRef }, { token: GLOBAL_ACTION_CATALOG, optional: true }, { token: SETTINGS_PANEL_DATA, optional: true }], target: i0.ɵɵFactoryTarget.Component });
31494
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDynamicFormConfigEditor, isStandalone: true, selector: "praxis-dynamic-form-config-editor", providers: [FormConfigService], viewQueries: [{ propertyName: "jsonEditor", first: true, predicate: JsonConfigEditorComponent, descendants: true }, { propertyName: "cascadeManager", first: true, predicate: CascadeManagerTabComponent, descendants: true }], ngImport: i0, template: "<div class=\"mobile-tab-selector\">\n <mat-form-field appearance=\"outline\" class=\"mobile-tab-selector__field\">\n <mat-label>{{ tx('config.tabs.mobileLabel', 'Se\u00E7\u00E3o do editor') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedConfigTabIndex\" data-testid=\"dynamic-form-config-editor-mobile-tabs\">\n @for (tab of configTabOptions; track tab.key) {\n <mat-option [value]=\"tab.index\">{{ tab.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n\n<mat-tab-group class=\"config-tabs\" data-testid=\"dynamic-form-config-editor-tabs\" [(selectedIndex)]=\"selectedConfigTabIndex\">\n <mat-tab [label]=\"configTabLabel('general')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-geral\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.title', 'Dados do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.general.subtitle', 'Defina o modo de dados e o contexto de edi\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.general.inputMode.label', 'Modo de dados') }}</mat-label>\n <mat-select [(ngModel)]=\"inputMode\" (ngModelChange)=\"onInputModeChange()\">\n <mat-option value=\"create\">{{ tx('config.general.inputMode.create', 'create') }}</mat-option>\n <mat-option value=\"edit\">{{ tx('config.general.inputMode.edit', 'edit') }}</mat-option>\n <mat-option value=\"view\">{{ tx('config.general.inputMode.view', 'view') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"block-status\" [class.block-status--implicit]=\"!isBindingsBlockPersisted()\">\n <strong>{{ tx('config.general.bindings.label', 'Bindings') }}</strong>\n @if (isBindingsBlockPersisted()) {\n <span>{{ tx('config.general.bindings.persisted', '`bindings.mode` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.general.bindings.implicit', 'Bloco ausente no documento can\u00F4nico. O valor exibido \u00E9 fallback visual e n\u00E3o ser\u00E1 salvo at\u00E9 voc\u00EA editar este campo.') }}\n }\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.common.understand', 'Entenda:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.general.inputMode.tooltip', 'O mode controla o fluxo (create/edit/view). enableCustomization s\u00F3 libera edi\u00E7\u00E3o do layout e n\u00E3o altera o mode.')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n\n @if (hasResolvedRuntimeContract()) {\n <mat-card\n class=\"section-card\"\n data-testid=\"config-tab-runtime-contract\"\n >\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.runtimeContract.title', 'Contrato Runtime Resolvido') }}</h3>\n <p class=\"text-caption\">\n {{ tx('config.general.runtimeContract.subtitle', 'Visualiza\u00E7\u00E3o somente leitura do contrato backend resolvido pelo host atual.') }}\n </p>\n </div>\n </div>\n <div class=\"block-status block-status--readonly\">\n <strong>{{ tx('config.general.runtimeContract.runtimeLabel', 'Runtime') }}</strong>\n <span>\n {{ tx('config.general.runtimeContract.readonly', 'Esses valores v\u00EAm do host/runtime atual e n\u00E3o s\u00E3o persistidos em `bindings` nem em `contextSnapshot`.') }}\n </span>\n </div>\n <div class=\"runtime-contract-grid\">\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaUrl', 'Schema URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.schemaUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaSource', 'Origem do schema') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.schemaSource) }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitMethod', 'Submit method') }}</span>\n <strong>{{ runtimeContract?.submitMethod || '\u2014' }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitUrl', 'Submit URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.submitUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitSource', 'Origem do submit') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.submitSource) }}</strong>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n }\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('schema')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-schema\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.schema.title', 'Valida\u00E7\u00E3o de schema') }}</h3>\n <p class=\"text-caption\">{{ tx('config.schema.subtitle', 'Controle avisos quando o schema do servidor mudar.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.notify.label', 'Notificar quando desatualizado') }}</mat-label>\n <mat-select [(ngModel)]=\"schemaPrefs.notifyIfOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-notify')\">\n <mat-option value=\"both\">{{ tx('config.schema.notify.both', 'Banner + Snackbar') }}</mat-option>\n <mat-option value=\"inline\">{{ tx('config.schema.notify.inline', 'Somente Banner') }}</mat-option>\n <mat-option value=\"snackbar\">{{ tx('config.schema.notify.snackbar', 'Somente Snackbar') }}</mat-option>\n <mat-option value=\"none\">{{ tx('config.schema.notify.none', 'Nenhum') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.snooze.label', 'Intervalo de sil\u00EAncio (ms)') }}</mat-label>\n <input matInput type=\"number\" [(ngModel)]=\"schemaPrefs.snoozeMs\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-snooze')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"schemaPrefs.autoOpenSettingsOnOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-auto-open')\">\n {{ tx('config.schema.autoOpenSettings', 'Abrir configura\u00E7\u00F5es automaticamente') }}\n </mat-slide-toggle>\n </div>\n @if (serverMeta) {\n <div class=\"form-row\">\n <div class=\"meta-card\">\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.serverHash', 'Server hash') }}</span>\n <strong>{{ serverMeta.serverHash || '\u2014' }}</strong>\n </div>\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.lastVerifiedAt', '\u00DAltima verifica\u00E7\u00E3o') }}</span>\n <strong>{{ serverMeta.lastVerifiedAt || '\u2014' }}</strong>\n </div>\n </div>\n </div>\n }\n <div class=\"block-status\" [class.block-status--implicit]=\"!isSchemaPrefsBlockPersisted()\">\n <strong>{{ tx('config.schema.prefs.label', 'Schema Prefs') }}</strong>\n @if (isSchemaPrefsBlockPersisted()) {\n <span>{{ tx('config.schema.prefs.persisted', '`contextSnapshot.schemaPrefs` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.schema.prefs.implicit', 'Bloco ausente no documento can\u00F4nico. Os controles exibem fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('layout')\">\n <div class=\"tab-content tab-content--full\" data-testid=\"config-tab-panel-layout\">\n <div class=\"section-header section-header--compact\">\n <div>\n <h3>{{ tx('config.layout.title', 'Layout do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.layout.subtitle', 'Organize se\u00E7\u00F5es, linhas e campos com drag & drop.') }}</p>\n </div>\n </div>\n <div class=\"section-body section-body--flex\">\n <praxis-layout-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"\n (select)=\"onLayoutSelect($event)\"></praxis-layout-editor>\n </div>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hooks')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-hooks\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hooks.title', 'Hooks de ciclo de vida') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hooks.subtitle', 'Automatize a\u00E7\u00F5es nos eventos do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-hooks-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-hooks-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n @if (isPresentationMode) {\n <mat-tab [label]=\"configTabLabel('presentation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-presentation\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.presentation.title', 'Modo Apresenta\u00E7\u00E3o') }}</h3>\n <p class=\"text-caption\">{{ tx('config.presentation.subtitle', 'Configura\u00E7\u00F5es de exibi\u00E7\u00E3o aplicadas somente ao modo apresenta\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <div class=\"presentation-layout\">\n <div class=\"presentation-controls\">\n <div class=\"block-status control-span\" [class.block-status--implicit]=\"!isPresentationBlockPersisted()\">\n <strong>{{ tx('config.presentation.block.label', 'Presentation') }}</strong>\n @if (isPresentationBlockPersisted()) {\n <span>{{ tx('config.presentation.block.persisted', '`contextSnapshot.presentation` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.presentation.block.implicit', 'Bloco ausente no documento can\u00F4nico. A pr\u00E9-visualiza\u00E7\u00E3o usa fallback local e n\u00E3o ser\u00E1 salva at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelPosition.label', 'Posi\u00E7\u00E3o do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelPosition\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-position')\" [attr.aria-label]=\"tx('config.presentation.labelPosition.ariaLabel', 'Posi\u00E7\u00E3o do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"above\">\n <mat-icon>view_stream</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.above', 'Acima') }}</span>\n </mat-button-toggle>\n <mat-button-toggle value=\"left\">\n <mat-icon>view_column</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.left', '\u00C0 esquerda') }}</span>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.density.label', 'Densidade') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.density\" (ngModelChange)=\"onPresentationPrefsChange('presentation-density')\" [attr.aria-label]=\"tx('config.presentation.density.ariaLabel', 'Densidade')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"comfortable\">{{ tx('config.presentation.density.comfortable', 'Confort\u00E1vel') }}</mat-button-toggle>\n <mat-button-toggle value=\"cozy\">{{ tx('config.presentation.density.cozy', 'Intermedi\u00E1ria') }}</mat-button-toggle>\n <mat-button-toggle value=\"compact\">{{ tx('config.presentation.density.compact', 'Compacta') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelAlign.label', 'Alinhamento do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-align')\" [attr.aria-label]=\"tx('config.presentation.labelAlign.ariaLabel', 'Alinhamento do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.valueAlign.label', 'Alinhamento do valor') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.valueAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-align')\" [attr.aria-label]=\"tx('config.presentation.valueAlign.ariaLabel', 'Alinhamento do valor')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelFontSize.label', 'Tamanho do r\u00F3tulo') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" [(ngModel)]=\"presentationPrefs.labelFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-font-size')\"\n [placeholder]=\"tx('config.presentation.labelFontSize.placeholder', 'ex.: 12')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.valueFontSize.label', 'Tamanho do valor') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" [(ngModel)]=\"presentationPrefs.valueFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-font-size')\"\n [placeholder]=\"tx('config.presentation.valueFontSize.placeholder', 'ex.: 16')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelWidth.label', 'Largura do r\u00F3tulo (label \u00E0 esquerda)') }}</mat-label>\n <input matInput type=\"number\" min=\"60\" [(ngModel)]=\"presentationPrefs.labelWidth\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-width')\"\n [placeholder]=\"tx('config.presentation.labelWidth.placeholder', 'ex.: 140')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control control--inline\">\n <mat-slide-toggle [(ngModel)]=\"presentationPrefs.compact\" (ngModelChange)=\"onPresentationPrefsChange('presentation-compact')\">\n {{ tx('config.presentation.options.compactMode', 'Modo compacto') }}\n </mat-slide-toggle>\n <mat-checkbox [(ngModel)]=\"truncatePreview\">\n {{ tx('config.presentation.options.truncateValues', 'Truncar valores') }}\n </mat-checkbox>\n </div>\n </div>\n <div class=\"presentation-preview\">\n <h4>{{ tx('config.presentation.preview.title', 'Pr\u00E9-visualiza\u00E7\u00E3o') }}</h4>\n <div class=\"preview-card\">\n <div class=\"praxis-dynamic-form presentation-mode\" [ngClass]=\"{\n 'pres-compact': !!presentationPrefs.compact,\n 'pres-label-left': presentationPrefs.labelPosition === 'left',\n 'pres-label-above': presentationPrefs.labelPosition === 'above',\n 'pres-density-compact': presentationPrefs.density === 'compact',\n 'pres-density-cozy': presentationPrefs.density === 'cozy'\n }\" [style.--pfx-pres-label-size]=\"(presentationPrefs.labelFontSize || 12) + 'px'\"\n [style.--pfx-pres-value-size]=\"(presentationPrefs.valueFontSize || 16) + 'px'\"\n [style.--pfx-pres-label-width]=\"(presentationPrefs.labelWidth || 140) + 'px'\"\n [style.--pfx-pres-label-align]=\"presentationPrefs.labelAlign || 'start'\"\n [style.--pfx-pres-value-align]=\"presentationPrefs.valueAlign || 'start'\">\n @for (item of previewItems; track item) {\n <div class=\"preview-row\">\n <span class=\"praxis-presentation__label\">{{ item.label }}</span>\n <span class=\"praxis-presentation__value\" [title]=\"truncatePreview ? item.value : null\"\n [style.maxWidth]=\"truncatePreview ? '280px' : null\"\n [style.overflow]=\"truncatePreview ? 'hidden' : null\"\n [style.textOverflow]=\"truncatePreview ? 'ellipsis' : null\"\n [style.whiteSpace]=\"truncatePreview ? 'nowrap' : 'normal'\">\n {{ item.value }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.common.understand', 'Entenda:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.presentation.help.tooltip', 'Ajustes aplicam somente ao Modo Apresenta\u00E7\u00E3o e s\u00E3o salvos por formul\u00E1rio (via CSS/Classes).')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n }\n <mat-tab [label]=\"configTabLabel('behavior')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-comportamento\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.behavior.title', 'Comportamento') }}</h3>\n <p class=\"text-caption\">{{ tx('config.behavior.subtitle', 'Ajuste valida\u00E7\u00F5es e respostas do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-behavior-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-behavior-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hints')\">\n <div class=\"tab-content tab-content--dense\" data-testid=\"config-tab-panel-hints\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hints.title', 'Dicas dos modos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hints.subtitle', 'Personalize textos de apoio para modos de dados e estados de UI.') }}</p>\n </div>\n </div>\n <p class=\"text-caption\">{{ tx('config.hints.description', 'Personalize os textos usados como tooltip/hint para modos de dados e modos globais de UI.') }}</p>\n\n <div class=\"grid-2-cols grid-2-cols--compact\">\n <section>\n <h4>{{ tx('config.hints.dataModes.title', 'Modos de dados') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.create.label', 'Criar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.create\"\n (ngModelChange)=\"updateDirtyState('hints-data-create')\" [placeholder]=\"tx('config.hints.dataModes.create.placeholder', 'Ex.: Preencha os campos obrigat\u00F3rios.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.edit.label', 'Editar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.edit\"\n (ngModelChange)=\"updateDirtyState('hints-data-edit')\" [placeholder]=\"tx('config.hints.dataModes.edit.placeholder', 'Ex.: Revise os dados antes de salvar.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.view.label', 'Visualizar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.view\"\n (ngModelChange)=\"updateDirtyState('hints-data-view')\" [placeholder]=\"tx('config.hints.dataModes.view.placeholder', 'Ex.: Visualiza\u00E7\u00E3o somente leitura.')\" />\n </mat-form-field>\n </section>\n\n <section>\n <h4>{{ tx('config.hints.uiModes.title', 'Modos de UI') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.presentation.label', 'Apresenta\u00E7\u00E3o') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.presentation\"\n (ngModelChange)=\"updateDirtyState('hints-ui-presentation')\" [placeholder]=\"tx('config.hints.uiModes.presentation.placeholder', 'Ex.: Modo compacto para leitura r\u00E1pida.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.readonly.label', 'Leitura (readonly)') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.readonly\"\n (ngModelChange)=\"updateDirtyState('hints-ui-readonly')\" [placeholder]=\"tx('config.hints.uiModes.readonly.placeholder', 'Ex.: Campos bloqueados para edi\u00E7\u00E3o.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.disabled.label', 'Desabilitado') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.disabled\"\n (ngModelChange)=\"updateDirtyState('hints-ui-disabled')\" [placeholder]=\"tx('config.hints.uiModes.disabled.placeholder', 'Ex.: Fun\u00E7\u00E3o indispon\u00EDvel no momento.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.visible.label', 'Vis\u00EDvel') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.visible\"\n (ngModelChange)=\"updateDirtyState('hints-ui-visible')\" [placeholder]=\"tx('config.hints.uiModes.visible.placeholder', 'Ex.: Campo exibido conforme permiss\u00F5es.')\"></textarea>\n </mat-form-field>\n </section>\n </div>\n\n <section>\n <h4>{{ tx('config.helpPresentation.title', 'Apresenta\u00E7\u00E3o das ajudas dos campos') }}</h4>\n <p class=\"text-caption\">{{ tx('config.helpPresentation.description', 'Controle como hint/helpText dos campos aparece em formul\u00E1rios densos. Erros de valida\u00E7\u00E3o continuam inline.') }}</p>\n <div class=\"grid-3-cols\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.display.label', 'Exibi\u00E7\u00E3o') }}</mat-label>\n <mat-select [ngModel]=\"helpPresentationDraft.display\" (ngModelChange)=\"onHelpPresentationDisplayChange($event)\">\n <mat-option value=\"inline\">{{ tx('config.helpPresentation.display.inline', 'Inline') }}</mat-option>\n <mat-option value=\"popover\">{{ tx('config.helpPresentation.display.popover', '\u00CDcone de ajuda') }}</mat-option>\n <mat-option value=\"auto\">{{ tx('config.helpPresentation.display.auto', 'Autom\u00E1tica') }}</mat-option>\n <mat-option value=\"hidden\">{{ tx('config.helpPresentation.display.hidden', 'Oculta') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.inlineMaxLength.label', 'Limite inline') }}</mat-label>\n <input matInput type=\"number\" min=\"0\" [ngModel]=\"helpPresentationDraft.inlineMaxLength\"\n (ngModelChange)=\"onHelpPresentationInlineMaxLengthChange($event)\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.preferPopoverForControls.label', 'Preferir \u00EDcone em') }}</mat-label>\n <input matInput [ngModel]=\"getHelpPreferPopoverControlsText()\"\n (ngModelChange)=\"onHelpPreferPopoverControlsChange($event)\"\n [placeholder]=\"tx('config.helpPresentation.preferPopoverForControls.placeholder', 'toggle, checkbox, select')\" />\n </mat-form-field>\n </div>\n </section>\n\n <div class=\"actions-row\">\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"restoreHintsDefaults()\">\n <mat-icon>restore</mat-icon>\n {{ tx('config.hints.actions.restoreDefaults', 'Restaurar padr\u00F5es') }}\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('actions')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-acoes\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.actions.title', 'A\u00E7\u00F5es do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.actions.subtitle', 'Configure bot\u00F5es padr\u00E3o e a\u00E7\u00F5es customizadas.') }}</p>\n </div>\n </div>\n <praxis-actions-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-actions-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('rules')\">\n <div class=\"tab-content visual-builder-content\" data-testid=\"config-tab-panel-regras\">\n <div class=\"builder-header\">\n <div>\n <h3>{{ tx('config.rules.title', 'Regras visuais') }}</h3>\n <p class=\"text-caption\">{{ tx('config.rules.subtitle', 'Defina visibilidade, estilos e rea\u00E7\u00F5es baseadas em condi\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n @if (ruleDiagnostics.length) {\n <div class=\"rules-diagnostics\" data-testid=\"rules-diagnostics-panel\">\n <div class=\"rules-diagnostics__summary\">\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--total\">\n {{ tx('config.rules.summary.total', '{{count}} regras', { count: ruleDiagnosticsSummary.total }) }}\n </span>\n @if (ruleDiagnosticsSummary.invalid) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--error\">\n {{ tx('config.rules.summary.invalid', '{{count}} inv\u00E1lidas', { count: ruleDiagnosticsSummary.invalid }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.unsupported) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.unsupported', '{{count}} com propriedades rejeitadas', { count: ruleDiagnosticsSummary.unsupported }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.runtimeOnly) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.runtimeOnly', '{{count}} runtime only', { count: ruleDiagnosticsSummary.runtimeOnly }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.pendingReview) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.pendingReview', '{{count}} pendentes de revis\u00E3o', { count: ruleDiagnosticsSummary.pendingReview }) }}\n </span>\n }\n </div>\n <div class=\"rules-diagnostics__list\" [attr.aria-label]=\"tx('config.rules.diagnostics.ariaLabel', 'Diagn\u00F3stico das regras')\">\n @for (diagnostic of ruleDiagnostics; track diagnostic) {\n <article class=\"rules-diagnostics__item\"\n [class.rules-diagnostics__item--error]=\"getRuleStatusTone(diagnostic) === 'error'\"\n [class.rules-diagnostics__item--warn]=\"getRuleStatusTone(diagnostic) === 'warn'\">\n <div>\n <strong>{{ diagnostic.ruleName || diagnostic.ruleId }}</strong>\n <span>\n {{ tx('config.rules.diagnostics.targetConditionSummary', '{{targets}} alvo(s) \u00B7 {{conditions}} campo(s) na condi\u00E7\u00E3o', { targets: diagnostic.targetRefs.length, conditions: diagnostic.conditionRefs.length }) }}\n </span>\n @if (getRuleDiagnosticDetails(diagnostic).length) {\n <ul class=\"rules-diagnostics__details\">\n @for (detail of getRuleDiagnosticDetails(diagnostic); track detail) {\n <li>{{ detail }}</li>\n }\n </ul>\n }\n </div>\n <div class=\"rules-diagnostics__actions\">\n <span class=\"rules-diagnostics__status\">{{ getRuleStatusLabel(diagnostic) }}</span>\n @if (canApplyRulePropertyFix(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.fix.tooltip', 'Aplicar whitelist e saneamento de propriedades nesta regra')\"\n (click)=\"applyRulePropertyFix(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">auto_fix_high</mat-icon>\n {{ tx('config.rules.actions.fix', 'Corrigir') }}\n </button>\n }\n @if (diagnostic.status.includes('llm-generated-pending-review')) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [disabled]=\"!canAcceptPendingLlmRule(diagnostic)\"\n [matTooltip]=\"canAcceptPendingLlmRule(diagnostic) ? tx('config.rules.actions.accept.tooltip.ready', 'Aceitar sugest\u00E3o e atualizar estado visual') : tx('config.rules.actions.accept.tooltip.blocked', 'Corrija alvo, condi\u00E7\u00E3o e propriedades antes de aceitar')\"\n (click)=\"acceptPendingLlmRule(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.rules.actions.accept', 'Aceitar') }}\n </button>\n }\n @if (canOpenRuleJsonReview(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.reviewJson.tooltip', 'Abrir a aba JSON para revisar esta regra sem convers\u00E3o visual')\"\n (click)=\"openRuleJsonReview(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">data_object</mat-icon>\n {{ tx('config.rules.actions.reviewJson', 'Ver JSON') }}\n </button>\n }\n </div>\n </article>\n }\n </div>\n </div>\n } @else {\n <div class=\"rules-diagnostics rules-diagnostics--empty\" data-testid=\"rules-diagnostics-empty\">\n {{ tx('config.rules.empty', 'Nenhuma regra definida ainda. Crie uma regra para ver alvos, condi\u00E7\u00E3o, propriedades e compatibilidade do builder.') }}\n </div>\n }\n <praxis-visual-builder [config]=\"ruleBuilderConfig\" [initialRules]=\"ruleBuilderState\"\n (rulesChanged)=\"onRulesChanged($event)\"></praxis-visual-builder>\n <praxis-rule-properties-panel\n [rules]=\"currentRules\"\n [visualBlockNodes]=\"visualBlockNodeOptions\"\n (rulesChange)=\"onRulePropertiesChanged($event)\"\n ></praxis-rule-properties-panel>\n <mat-card class=\"command-rules-card\" data-testid=\"form-command-rules-editor\">\n <mat-card-title>{{ tx('config.commandRules.title', 'Comandos condicionais') }}</mat-card-title>\n <mat-card-subtitle>{{ tx('config.commandRules.subtitle', 'Execute a\u00E7\u00F5es globais quando uma condi\u00E7\u00E3o do formul\u00E1rio for satisfeita.') }}</mat-card-subtitle>\n <mat-card-content>\n <div class=\"command-rules-grid\">\n <div class=\"command-rules-toolbar\">\n <mat-form-field appearance=\"fill\" class=\"command-rules-select\">\n <mat-label>{{ tx('config.commandRules.command.label', 'Comando') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedCommandRuleId\" (selectionChange)=\"onCommandRuleSelectionChange()\">\n @for (rule of commandRules; track rule) {\n <mat-option [value]=\"rule.id\">\n {{ rule.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <button mat-stroked-button type=\"button\" (click)=\"addCommandRule()\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n {{ tx('config.commandRules.actions.add', 'Adicionar') }}\n </button>\n <button mat-stroked-button color=\"warn\" type=\"button\" (click)=\"deleteCommandRule()\" [disabled]=\"!selectedCommandRuleId\">\n <mat-icon aria-hidden=\"true\">delete</mat-icon>\n {{ tx('config.commandRules.actions.remove', 'Remover') }}\n </button>\n </div>\n\n @if (selectedCommandRuleId) {\n <div class=\"command-rule-condition-builder command-rules-full\">\n <praxis-visual-builder\n mode=\"condition\"\n [config]=\"ruleBuilderConfig\"\n [initialCondition]=\"commandRuleCondition\"\n (conditionChanged)=\"onCommandConditionChanged($event)\"\n ></praxis-visual-builder>\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.conditionJson.label', 'Condi\u00E7\u00E3o JSON Logic') }}</mat-label>\n <textarea\n matInput\n rows=\"5\"\n [(ngModel)]=\"commandRuleConditionJson\"\n [attr.aria-label]=\"tx('config.commandRules.conditionJson.ariaLabel', 'Condi\u00E7\u00E3o JSON Logic do comando condicional')\"\n ></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.globalAction.label', 'A\u00E7\u00E3o global') }}</mat-label>\n <mat-select [(ngModel)]=\"commandRuleActionId\" (selectionChange)=\"onCommandActionChange()\">\n @for (action of globalActionCatalog; track action) {\n <mat-option [value]=\"action.id\">\n {{ action.label || action.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.distinctBy.label', 'distinctBy') }}</mat-label>\n <input matInput [(ngModel)]=\"commandRuleDistinctBy\" [placeholder]=\"tx('config.commandRules.distinctBy.placeholder', 'ex.: idade')\" />\n </mat-form-field>\n\n @if (commandRuleActionSchema; as actionSchema) {\n <div\n class=\"command-rules-payload-fields command-rules-full\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.structuredPayload.title', 'Payload estruturado') }}</div>\n @if (actionSchema.editorMode !== 'surface-open') {\n @for (field of actionSchema.fields; track field) {\n @if (shouldShowCommandActionField(field)) {\n @if (field.type === 'toggle') {\n <mat-slide-toggle\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n >\n {{ field.label }}\n </mat-slide-toggle>\n } @else {\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ field.label }}</mat-label>\n @if (field.type === 'textarea' || field.type === 'json') {\n <textarea\n matInput\n [rows]=\"field.rows || (field.type === 'json' ? 3 : 2)\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || (field.type === 'json' ? '{ }' : '')\"\n [required]=\"isCommandActionFieldRequired(field)\"\n ></textarea>\n } @else {\n @if (field.type === 'select') {\n <mat-select\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [required]=\"isCommandActionFieldRequired(field)\"\n >\n @for (option of field.options || []; track option) {\n <mat-option [value]=\"option.value\">\n {{ option.label }}\n </mat-option>\n }\n </mat-select>\n } @else {\n <input\n matInput\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || ''\"\n [required]=\"isCommandActionFieldRequired(field)\"\n />\n }\n }\n @if (field.hint) {\n <mat-hint>{{ field.hint }}</mat-hint>\n }\n @if (hasCommandActionFieldError(field.key)) {\n <mat-error>\n {{ getCommandActionFieldError(field.key) }}\n </mat-error>\n }\n @if (!hasCommandActionFieldError(field.key) && isCommandActionFieldMissing(field)) {\n <mat-error>\n {{ tx('config.commandRules.validation.requiredField', 'Campo obrigat\u00F3rio.') }}\n </mat-error>\n }\n </mat-form-field>\n }\n }\n }\n } @else {\n <praxis-surface-open-action-editor\n class=\"command-rules-surface-editor\"\n data-testid=\"form-command-rule-surface-open-editor\"\n [value]=\"commandRuleSurfaceOpenPayload\"\n hostKind=\"dynamic-form\"\n (valueChange)=\"onCommandSurfaceOpenPayloadChange($event)\"\n ></praxis-surface-open-action-editor>\n }\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.advancedPayload.label', 'Payload JSON avan\u00E7ado') }}</mat-label>\n <textarea\n matInput\n rows=\"4\"\n [(ngModel)]=\"commandRulePayloadJson\"\n [attr.aria-label]=\"tx('config.commandRules.advancedPayload.ariaLabel', 'Payload JSON da a\u00E7\u00E3o global')\"\n ></textarea>\n </mat-form-field>\n\n <div class=\"command-rules-options\">\n <mat-slide-toggle [(ngModel)]=\"commandRuleDistinct\">{{ tx('config.commandRules.options.distinct', 'Evitar repeti\u00E7\u00E3o enquanto a condi\u00E7\u00E3o permanecer verdadeira') }}</mat-slide-toggle>\n <mat-slide-toggle [(ngModel)]=\"commandRuleRunOnInitialEvaluation\">{{ tx('config.commandRules.options.runOnInitialEvaluation', 'Executar tamb\u00E9m na avalia\u00E7\u00E3o inicial') }}</mat-slide-toggle>\n </div>\n\n @if (commandRuleAuthoringError) {\n <div class=\"preview-error command-rules-full\">\n <mat-icon aria-hidden=\"true\">warning</mat-icon>\n <span>{{ commandRuleAuthoringError }}</span>\n </div>\n }\n\n <div\n class=\"command-rule-preview command-rules-full\"\n [class.command-rule-preview--invalid]=\"commandRulePreview.state === 'invalid'\"\n data-testid=\"command-rule-preview\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.preview.title', 'Preview do comando') }}</div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.mode', 'Modo') }}</span>\n <strong>{{ commandRulePreview.executionMode }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.action', 'A\u00E7\u00E3o') }}</span>\n <strong>{{ commandRulePreview.actionId || '\u2014' }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.policy', 'Policy') }}</span>\n <code>{{ commandRulePreview.policy | json }}</code>\n </div>\n @if (commandRulePreview.diagnostics.length) {\n <div class=\"command-rule-preview__diagnostics\">\n <mat-icon aria-hidden=\"true\">{{ commandRulePreview.state === 'invalid' ? 'warning' : 'visibility' }}</mat-icon>\n <span>{{ commandRulePreview.diagnostics[0] }}</span>\n </div>\n }\n </div>\n\n <div class=\"command-rules-actions\">\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"applyCommandRule()\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.commandRules.actions.apply', 'Aplicar comando') }}\n </button>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('cascades')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-cascatas\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.cascades.title', 'Depend\u00EAncias entre campos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.cascades.subtitle', 'Configure cascatas e carregamento entre campos.') }}</p>\n </div>\n </div>\n <praxis-cascade-manager-tab [fields]=\"editedConfig.fieldMetadata || []\"\n (apply)=\"onCascadeApply($event)\"></praxis-cascade-manager-tab>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('messages')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-mensagens\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.messages.title', 'Mensagens e feedback') }}</h3>\n <p class=\"text-caption\">{{ tx('config.messages.subtitle', 'Padronize textos de sucesso, erro e confirma\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n <praxis-messages-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-messages-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('navigation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-navegacao\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.navigation.title', 'Navega\u00E7\u00E3o de retorno') }}</h3>\n <p class=\"text-caption\">{{ tx('config.navigation.subtitle', 'Defina o comportamento do bot\u00E3o Voltar em fluxos CRUD.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.navigation.returnTo.label', 'Rota de retorno') }}</mat-label>\n <input matInput id=\"returnTo\" [(ngModel)]=\"backConfig!.returnTo\" (ngModelChange)=\"onBackConfigChange()\" [placeholder]=\"tx('config.navigation.returnTo.placeholder', '/funcionarios')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"backConfig!.confirmOnDirty\" (ngModelChange)=\"onBackConfigChange()\">\n {{ tx('config.navigation.confirmOnDirty.label', 'Confirmar ao sair com altera\u00E7\u00F5es') }}\n </mat-slide-toggle>\n </div>\n <div class=\"block-status\" [class.block-status--implicit]=\"!isBackConfigBlockPersisted()\">\n <strong>{{ tx('config.navigation.backConfig.label', 'Back Config') }}</strong>\n @if (isBackConfigBlockPersisted()) {\n <span>{{ tx('config.navigation.backConfig.persisted', '`contextSnapshot.backConfig` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.navigation.backConfig.implicit', 'Bloco ausente no documento can\u00F4nico. Os valores exibidos s\u00E3o fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.navigation.note.label', 'Observa\u00E7\u00E3o:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.navigation.note.tooltip', 'Afeta o fluxo de navega\u00E7\u00E3o do CRUD e pode ser sobreposto por metadados do recurso.')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('json')\">\n <div class=\"tab-content json-tab-content\" data-testid=\"config-tab-panel-json\">\n <mat-card class=\"section-card section-card--json\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.json.title', 'Configura\u00E7\u00E3o JSON') }}</h3>\n <p class=\"text-caption\">{{ tx('config.json.subtitle', 'Edi\u00E7\u00E3o avan\u00E7ada do documento can\u00F4nico de autoria do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <form-json-config-editor [document]=\"jsonDocument\" (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\" (editorEvent)=\"onJsonEditorEvent($event)\">\n </form-json-config-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n</mat-tab-group>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-width:0}.mobile-tab-selector{display:none;flex:0 0 auto;padding:8px 16px 0;background:var(--md-sys-color-surface)}.mobile-tab-selector__field{width:100%}.config-tabs{flex:1 1 auto;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs{display:flex;flex-direction:column}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-wrapper{flex:1;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-content{height:100%;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;padding:0!important}.tab-content{padding:16px 20px 20px;flex:1;min-width:0;box-sizing:border-box}.json-tab-content{min-width:0;padding:12px 16px 16px}.section-card--json{display:flex;flex:1;min-height:calc(100vh - 180px);border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.section-card--json>mat-card-content{display:flex;flex:1;min-width:0;min-height:0;flex-direction:column}.section-card--json form-json-config-editor{display:block;flex:1;min-width:0;min-height:0}.form-row{display:block;margin-bottom:12px}.form-grid{display:grid;gap:12px}.section-help{display:inline-flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:12px}.section-help__label{font-weight:500}.grid-2-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}.grid-2-cols--compact{gap:12px}.w-100{width:100%}.visual-builder-content{padding:0!important;height:100%;min-width:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:16px}.visual-builder-content>praxis-visual-builder{flex:0 0 auto;min-width:0;min-height:clamp(360px,48vh,560px)}.visual-builder-content>praxis-rule-properties-panel{flex:0 0 auto;display:block;min-width:0;padding:0 16px 24px;box-sizing:border-box}.rules-diagnostics{flex:0 0 auto;display:grid;gap:10px;padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.rules-diagnostics--empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.rules-diagnostics__summary,.rules-diagnostics__list{display:flex;flex-wrap:wrap;gap:8px}.rules-diagnostics__pill{display:inline-flex;align-items:center;min-height:24px;padding:3px 9px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:12px;font-weight:600}.rules-diagnostics__pill--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container) 72%,transparent);color:var(--md-sys-color-on-tertiary-container)}.rules-diagnostics__pill--error{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.rules-diagnostics__item{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;min-width:min(100%,280px);padding:8px 10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container)}.rules-diagnostics__item>div{display:grid;gap:2px;min-width:0}.rules-diagnostics__item strong{color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rules-diagnostics__item span{color:var(--md-sys-color-on-surface-variant);font-size:11px}.rules-diagnostics__actions{flex:0 0 auto;display:flex;align-items:center;gap:8px}.rules-diagnostics__details{display:grid;gap:2px;margin:4px 0 0;padding-left:16px;color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35}.rules-diagnostics__details li{overflow-wrap:anywhere}.rules-diagnostics__item--warn{border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 52%,var(--md-sys-color-outline-variant))}.rules-diagnostics__item--error{border-color:var(--md-sys-color-error)}.rules-diagnostics__status{font-weight:600;margin-top:1px}.rules-diagnostics__action{min-width:0;height:28px;padding:0 10px;border-radius:999px;font-size:12px;line-height:1}.rules-diagnostics__action mat-icon{width:16px;height:16px;margin:0 4px 0 0;font-size:16px}.json-field{width:100%}.presentation-layout{display:flex;gap:20px;align-items:flex-start}.presentation-controls{flex:1 1 60%;display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px 18px}.control{display:flex;flex-direction:column}.control-span{grid-column:1/-1}.block-status{grid-column:1/-1;display:flex;gap:8px;align-items:flex-start;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 35%,transparent);color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.45}.block-status strong{min-width:112px;font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant)}.block-status--implicit{background:color-mix(in srgb,var(--md-sys-color-surface-variant) 42%,transparent);border:1px dashed var(--md-sys-color-outline)}.block-status--readonly{margin-bottom:12px}.block-status code{font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:11px}.control__label{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:6px}.toggle-group{width:100%}.control--inline{grid-column:1/-1;display:flex;gap:16px;align-items:center}.presentation-preview{flex:0 0 360px;position:sticky;top:16px}.preview-card{border:1px solid var(--md-sys-color-outline);border-radius:12px;padding:14px;background:var(--md-sys-color-surface-container)}.preview-row{display:flex;gap:8px;padding:6px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.preview-row:last-child{border-bottom:none}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.presentation-preview .praxis-presentation__label{color:var(--md-sys-color-on-surface-variant)}.presentation-preview .praxis-presentation__value{color:var(--md-sys-color-on-surface)}.presentation-preview .presentation-mode.pres-density-cozy .preview-row{padding:6px 0}.presentation-preview .presentation-mode.pres-density-compact .preview-row,.presentation-preview .presentation-mode.pres-compact .preview-row{padding:2px 0}.presentation-preview .presentation-mode.pres-label-left .preview-row{display:grid;grid-template-columns:var(--pfx-pres-label-width, 140px) 1fr;align-items:baseline;column-gap:10px}.presentation-preview .presentation-mode.pres-label-left .praxis-presentation__label{margin:0;text-align:var(--pfx-pres-label-align, start)}.presentation-preview .presentation-mode .praxis-presentation__value{text-align:var(--pfx-pres-value-align, start)}.presentation-preview h4{margin:0 0 8px;color:var(--md-sys-color-on-surface);font-size:1rem}.section-card{border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-level1, none)}.section-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.tab-content--dense{padding:12px 16px 16px}.tab-content--dense .section-header,.tab-content--dense .form-row{margin-bottom:8px}.section-header h3{margin:0;font-size:1.05rem;color:var(--md-sys-color-on-surface)}.text-caption{margin:6px 0 0;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.section-header--compact{margin-bottom:8px}.section-body{display:block}.section-body--flex{flex:1;min-height:0;display:flex;flex-direction:column}.builder-header{padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.builder-header h3{margin:0;font-size:1rem;color:var(--md-sys-color-on-surface)}.hint{margin:8px 0 0;padding:10px 12px;border-radius:10px;border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface-variant)}.meta-card{display:grid;gap:6px;padding:10px 12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.meta-row{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.meta-row strong{color:var(--md-sys-color-on-surface);font-weight:600}.runtime-contract-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.runtime-contract-field{display:grid;gap:6px;padding:12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.runtime-contract-label{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.runtime-contract-code{display:block;font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:12px;line-height:1.45;color:var(--md-sys-color-on-surface);word-break:break-word;white-space:normal}.command-rules-card{margin:16px;min-width:0;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container)}.command-rules-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:12px;align-items:start;min-width:0}.command-rules-toolbar,.command-rules-options,.command-rules-actions{grid-column:1/-1;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.command-rules-select{min-width:min(320px,100%)}.command-rules-full{grid-column:1/-1}.command-rule-condition-builder{min-height:420px;overflow:hidden;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-payload-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px;min-width:0;padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-section-title{grid-column:1/-1;font-size:12px;font-weight:600;color:var(--md-sys-color-on-surface-variant);text-transform:uppercase}.command-rules-surface-editor{grid-column:1/-1}.command-rule-preview{display:grid;gap:8px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.command-rule-preview--invalid{border-color:var(--md-sys-color-error)}.command-rule-preview__row{display:grid;grid-template-columns:minmax(96px,.35fr) minmax(0,1fr);gap:8px;align-items:start;min-width:0}.command-rule-preview__row span{color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:600}.command-rule-preview__row strong,.command-rule-preview__row code{min-width:0;overflow-wrap:anywhere}.command-rule-preview__diagnostics{display:flex;gap:8px;align-items:flex-start;color:var(--md-sys-color-on-surface-variant)}@media(max-width:768px){.mobile-tab-selector{display:block}::ng-deep .mat-mdc-tab-group.config-tabs>.mat-mdc-tab-header{display:none}.tab-content{padding:12px}.json-tab-content{padding:8px}.section-card--json{min-height:auto}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$3.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i6$3.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i7$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i7$1.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i7$1.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i7$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i5$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$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: i6$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$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: MatCheckboxModule }, { kind: "component", type: i12.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: MatSlideToggleModule }, { kind: "component", type: i5$2.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i7$2.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i7$2.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "component", type: JsonConfigEditorComponent, selector: "form-json-config-editor", inputs: ["config", "document"], outputs: ["configChange", "documentChange", "validationChange", "editorEvent"] }, { kind: "component", type: LayoutEditorComponent, selector: "praxis-layout-editor", inputs: ["config"], outputs: ["configChange", "select"] }, { kind: "component", type: BehaviorEditorComponent, selector: "praxis-behavior-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: ActionsEditorComponent$1, selector: "praxis-actions-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: MessagesEditorComponent, selector: "praxis-messages-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: HooksEditorComponent, selector: "praxis-hooks-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: RulePropertiesPanelComponent, selector: "praxis-rule-properties-panel", inputs: ["rules", "visualBlockNodes"], outputs: ["rulesChange"] }, { kind: "component", type: PraxisVisualBuilder, selector: "praxis-visual-builder", inputs: ["mode", "config", "initialRules", "initialCondition"], outputs: ["rulesChanged", "conditionChanged", "exportRequested", "importRequested"] }, { kind: "component", type: CascadeManagerTabComponent, selector: "praxis-cascade-manager-tab", inputs: ["fields", "connections"], outputs: ["apply", "cancel"] }, { kind: "component", type: SurfaceOpenActionEditorComponent, selector: "praxis-surface-open-action-editor", inputs: ["value", "hostKind"], outputs: ["valueChange"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }] });
31602
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisDynamicFormConfigEditor, isStandalone: true, selector: "praxis-dynamic-form-config-editor", providers: [FormConfigService, providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG)], viewQueries: [{ propertyName: "jsonEditor", first: true, predicate: JsonConfigEditorComponent, descendants: true }, { propertyName: "cascadeManager", first: true, predicate: CascadeManagerTabComponent, descendants: true }], ngImport: i0, template: "<div class=\"mobile-tab-selector\">\n <mat-form-field appearance=\"outline\" class=\"mobile-tab-selector__field\">\n <mat-label>{{ tx('config.tabs.mobileLabel', 'Se\u00E7\u00E3o do editor') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedConfigTabIndex\" data-testid=\"dynamic-form-config-editor-mobile-tabs\">\n @for (tab of configTabOptions; track tab.key) {\n <mat-option [value]=\"tab.index\">{{ tab.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n\n<mat-tab-group class=\"config-tabs\" data-testid=\"dynamic-form-config-editor-tabs\" [(selectedIndex)]=\"selectedConfigTabIndex\">\n <mat-tab [label]=\"configTabLabel('general')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-geral\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.title', 'Dados do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.general.subtitle', 'Defina o modo de dados e o contexto de edi\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <div class=\"form-modes\">\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.general.inputMode.label') }}</label>\n <mat-button-toggle-group [ngModel]=\"inputMode\" (ngModelChange)=\"inputMode = $event; onInputModeChange()\" [attr.aria-label]=\"tx('config.general.inputMode.label')\">\n <mat-button-toggle value=\"create\">{{ tx('config.general.inputMode.create') }}</mat-button-toggle>\n <mat-button-toggle value=\"edit\">{{ tx('config.general.inputMode.edit') }}</mat-button-toggle>\n <mat-button-toggle value=\"view\">{{ tx('config.general.inputMode.view') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n @if (supportsPresentationSettings) {\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.general.displayMode.label') }}</label>\n <mat-button-toggle-group [ngModel]=\"displayMode\" (ngModelChange)=\"onDisplayModeChange($event)\" [attr.aria-label]=\"tx('config.general.displayMode.label')\">\n <mat-button-toggle value=\"automatic\">{{ tx('config.general.displayMode.automatic') }}</mat-button-toggle>\n <mat-button-toggle value=\"fields\">{{ tx('config.general.displayMode.fields') }}</mat-button-toggle>\n <mat-button-toggle value=\"presentation\">{{ tx('config.general.displayMode.presentation') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <p class=\"display-result\" role=\"status\">{{ tx(displayModeHint) }}</p>\n @if (inputMode !== 'view' && inputPresentationMode === true) {\n <button mat-stroked-button type=\"button\" (click)=\"useViewMode()\">{{ tx('config.general.displayMode.useView') }}</button>\n }\n <button mat-button type=\"button\" (click)=\"openPresentationStyle()\">{{ tx('config.general.displayMode.openStyle') }}</button>\n }\n </div>\n </mat-card-content>\n </mat-card>\n\n @if (hasResolvedRuntimeContract()) {\n <mat-card\n class=\"section-card\"\n data-testid=\"config-tab-runtime-contract\"\n >\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.runtimeContract.title', 'Contrato Runtime Resolvido') }}</h3>\n <p class=\"text-caption\">\n {{ tx('config.general.runtimeContract.subtitle', 'Visualiza\u00E7\u00E3o somente leitura do contrato backend resolvido pelo host atual.') }}\n </p>\n </div>\n </div>\n <div class=\"block-status block-status--readonly\">\n <strong>{{ tx('config.general.runtimeContract.runtimeLabel', 'Runtime') }}</strong>\n <span>\n {{ tx('config.general.runtimeContract.readonly', 'Esses valores v\u00EAm do host/runtime atual e n\u00E3o s\u00E3o persistidos em `bindings` nem em `contextSnapshot`.') }}\n </span>\n </div>\n <div class=\"runtime-contract-grid\">\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaUrl', 'Schema URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.schemaUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaSource', 'Origem do schema') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.schemaSource) }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitMethod', 'Submit method') }}</span>\n <strong>{{ runtimeContract?.submitMethod || '\u2014' }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitUrl', 'Submit URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.submitUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitSource', 'Origem do submit') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.submitSource) }}</strong>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n }\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('schema')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-schema\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.schema.title', 'Valida\u00E7\u00E3o de schema') }}</h3>\n <p class=\"text-caption\">{{ tx('config.schema.subtitle', 'Controle avisos quando o schema do servidor mudar.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.notify.label', 'Notificar quando desatualizado') }}</mat-label>\n <mat-select [(ngModel)]=\"schemaPrefs.notifyIfOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-notify')\">\n <mat-option value=\"both\">{{ tx('config.schema.notify.both', 'Banner + Snackbar') }}</mat-option>\n <mat-option value=\"inline\">{{ tx('config.schema.notify.inline', 'Somente Banner') }}</mat-option>\n <mat-option value=\"snackbar\">{{ tx('config.schema.notify.snackbar', 'Somente Snackbar') }}</mat-option>\n <mat-option value=\"none\">{{ tx('config.schema.notify.none', 'Nenhum') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.snooze.label', 'Intervalo de sil\u00EAncio (ms)') }}</mat-label>\n <input matInput type=\"number\" [(ngModel)]=\"schemaPrefs.snoozeMs\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-snooze')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"schemaPrefs.autoOpenSettingsOnOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-auto-open')\">\n {{ tx('config.schema.autoOpenSettings', 'Abrir configura\u00E7\u00F5es automaticamente') }}\n </mat-slide-toggle>\n </div>\n @if (serverMeta) {\n <div class=\"form-row\">\n <div class=\"meta-card\">\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.serverHash', 'Server hash') }}</span>\n <strong>{{ serverMeta.serverHash || '\u2014' }}</strong>\n </div>\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.lastVerifiedAt', '\u00DAltima verifica\u00E7\u00E3o') }}</span>\n <strong>{{ serverMeta.lastVerifiedAt || '\u2014' }}</strong>\n </div>\n </div>\n </div>\n }\n <div class=\"block-status\" [class.block-status--implicit]=\"!isSchemaPrefsBlockPersisted()\">\n <strong>{{ tx('config.schema.prefs.label', 'Schema Prefs') }}</strong>\n @if (isSchemaPrefsBlockPersisted()) {\n <span>{{ tx('config.schema.prefs.persisted', '`contextSnapshot.schemaPrefs` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.schema.prefs.implicit', 'Bloco ausente no documento can\u00F4nico. Os controles exibem fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('layout')\">\n <div class=\"tab-content tab-content--full\" data-testid=\"config-tab-panel-layout\">\n <div class=\"section-header section-header--compact\">\n <div>\n <h3>{{ tx('config.layout.title', 'Layout do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.layout.subtitle', 'Organize se\u00E7\u00F5es, linhas e campos com drag & drop.') }}</p>\n </div>\n </div>\n <div class=\"section-body section-body--flex\">\n <praxis-layout-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"\n (select)=\"onLayoutSelect($event)\"></praxis-layout-editor>\n </div>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hooks')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-hooks\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hooks.title', 'Hooks de ciclo de vida') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hooks.subtitle', 'Automatize a\u00E7\u00F5es nos eventos do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-hooks-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-hooks-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n @if (isPresentationMode) {\n <mat-tab [label]=\"configTabLabel('presentation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-presentation\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.presentation.title', 'Modo Apresenta\u00E7\u00E3o') }}</h3>\n <p class=\"text-caption\">{{ tx('config.presentation.subtitle', 'Configura\u00E7\u00F5es de exibi\u00E7\u00E3o aplicadas somente ao modo apresenta\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <p class=\"display-result\" role=\"status\">{{ tx(displayModeHint) }}</p>\n <div class=\"presentation-layout\">\n <div class=\"presentation-controls\">\n <div class=\"block-status control-span\" [class.block-status--implicit]=\"!isPresentationBlockPersisted()\">\n <strong>{{ tx('config.presentation.block.label', 'Presentation') }}</strong>\n @if (isPresentationBlockPersisted()) {\n <span>{{ tx('config.presentation.block.persisted', '`contextSnapshot.presentation` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.presentation.block.implicit', 'Bloco ausente no documento can\u00F4nico. A pr\u00E9-visualiza\u00E7\u00E3o usa fallback local e n\u00E3o ser\u00E1 salva at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelPosition.label', 'Posi\u00E7\u00E3o do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelPosition\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-position')\" [attr.aria-label]=\"tx('config.presentation.labelPosition.ariaLabel', 'Posi\u00E7\u00E3o do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"above\">\n <mat-icon>view_stream</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.above', 'Acima') }}</span>\n </mat-button-toggle>\n <mat-button-toggle value=\"left\">\n <mat-icon>view_column</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.left', '\u00C0 esquerda') }}</span>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control control-span\">\n <label class=\"control__label\">{{ tx('config.presentation.density.label', 'Densidade') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.density\" (ngModelChange)=\"onPresentationPrefsChange('presentation-density')\" [attr.aria-label]=\"tx('config.presentation.density.ariaLabel', 'Densidade')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"comfortable\">{{ tx('config.presentation.density.comfortable', 'Confort\u00E1vel') }}</mat-button-toggle>\n <mat-button-toggle value=\"cozy\">{{ tx('config.presentation.density.cozy', 'Intermedi\u00E1ria') }}</mat-button-toggle>\n <mat-button-toggle value=\"compact\">{{ tx('config.presentation.density.compact', 'Compacta') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelAlign.label', 'Alinhamento do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-align')\" [attr.aria-label]=\"tx('config.presentation.labelAlign.ariaLabel', 'Alinhamento do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\" [aria-label]=\"tx('config.presentation.align.start')\" [matTooltip]=\"tx('config.presentation.align.start')\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\" [aria-label]=\"tx('config.presentation.align.center')\" [matTooltip]=\"tx('config.presentation.align.center')\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\" [aria-label]=\"tx('config.presentation.align.end')\" [matTooltip]=\"tx('config.presentation.align.end')\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.valueAlign.label', 'Alinhamento do valor') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.valueAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-align')\" [attr.aria-label]=\"tx('config.presentation.valueAlign.ariaLabel', 'Alinhamento do valor')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\" [aria-label]=\"tx('config.presentation.align.start')\" [matTooltip]=\"tx('config.presentation.align.start')\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\" [aria-label]=\"tx('config.presentation.align.center')\" [matTooltip]=\"tx('config.presentation.align.center')\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\" [aria-label]=\"tx('config.presentation.align.end')\" [matTooltip]=\"tx('config.presentation.align.end')\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelFontSize.label', 'Tamanho do r\u00F3tulo') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" step=\"any\" [(ngModel)]=\"presentationPrefs.labelFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-font-size')\"\n [placeholder]=\"tx('config.presentation.labelFontSize.placeholder', 'ex.: 12')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.valueFontSize.label', 'Tamanho do valor') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" step=\"any\" [(ngModel)]=\"presentationPrefs.valueFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-font-size')\"\n [placeholder]=\"tx('config.presentation.valueFontSize.placeholder', 'ex.: 16')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelWidth.label', 'Largura do r\u00F3tulo (label \u00E0 esquerda)') }}</mat-label>\n <input matInput type=\"number\" min=\"60\" [disabled]=\"presentationPrefs.labelPosition !== 'left'\" [(ngModel)]=\"presentationPrefs.labelWidth\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-width')\"\n [placeholder]=\"tx('config.presentation.labelWidth.placeholder', 'ex.: 140')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control control--inline\">\n <mat-slide-toggle [(ngModel)]=\"presentationPrefs.compact\" (ngModelChange)=\"onPresentationPrefsChange('presentation-compact')\">\n {{ tx('config.presentation.options.compactMode', 'Modo compacto') }}\n </mat-slide-toggle>\n <mat-checkbox [(ngModel)]=\"truncatePreview\">\n {{ tx('config.presentation.options.truncateValues', 'Truncar valores') }}\n </mat-checkbox>\n </div>\n </div>\n <div class=\"presentation-preview\">\n <h4>{{ tx('config.presentation.preview.title', 'Pr\u00E9-visualiza\u00E7\u00E3o') }}</h4>\n <p class=\"text-caption\">{{ tx('config.presentation.preview.sampleHint') }}</p>\n <div class=\"preview-card\">\n <div class=\"praxis-dynamic-form presentation-mode\" [ngClass]=\"{\n 'pres-compact': !!presentationPrefs.compact,\n 'pres-label-left': presentationPrefs.labelPosition === 'left',\n 'pres-label-above': presentationPrefs.labelPosition === 'above',\n 'pres-density-compact': presentationPrefs.density === 'compact',\n 'pres-density-cozy': presentationPrefs.density === 'cozy'\n }\" [style.--pfx-pres-label-size]=\"(presentationPrefs.labelFontSize || 12) + 'px'\"\n [style.--pfx-pres-value-size]=\"(presentationPrefs.valueFontSize || 16) + 'px'\"\n [style.--pfx-pres-label-width]=\"(presentationPrefs.labelWidth || 140) + 'px'\"\n [style.--pfx-pres-label-align]=\"presentationPrefs.labelAlign || 'start'\"\n [style.--pfx-pres-value-align]=\"presentationPrefs.valueAlign || 'start'\">\n @for (item of previewItems; track item) {\n <div class=\"preview-row\">\n <span class=\"praxis-presentation__label\">{{ item.label }}</span>\n <span class=\"praxis-presentation__value\" [attr.title]=\"truncatePreview ? item.value : null\"\n [style.maxWidth]=\"truncatePreview ? '280px' : null\"\n [style.overflow]=\"truncatePreview ? 'hidden' : null\"\n [style.textOverflow]=\"truncatePreview ? 'ellipsis' : null\"\n [style.whiteSpace]=\"truncatePreview ? 'nowrap' : 'normal'\">\n {{ item.value }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n }\n <mat-tab [label]=\"configTabLabel('behavior')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-comportamento\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.behavior.title', 'Comportamento') }}</h3>\n <p class=\"text-caption\">{{ tx('config.behavior.subtitle', 'Ajuste valida\u00E7\u00F5es e respostas do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-behavior-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-behavior-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hints')\">\n <div class=\"tab-content tab-content--dense\" data-testid=\"config-tab-panel-hints\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hints.title', 'Dicas dos modos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hints.subtitle', 'Personalize textos de apoio para modos de dados e estados de UI.') }}</p>\n </div>\n </div>\n <p class=\"text-caption\">{{ tx('config.hints.description', 'Personalize os textos usados como tooltip/hint para modos de dados e modos globais de UI.') }}</p>\n\n <div class=\"grid-2-cols grid-2-cols--compact\">\n <section>\n <h4>{{ tx('config.hints.dataModes.title', 'Modos de dados') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.create.label', 'Criar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.create\"\n (ngModelChange)=\"updateDirtyState('hints-data-create')\" [placeholder]=\"tx('config.hints.dataModes.create.placeholder', 'Ex.: Preencha os campos obrigat\u00F3rios.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.edit.label', 'Editar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.edit\"\n (ngModelChange)=\"updateDirtyState('hints-data-edit')\" [placeholder]=\"tx('config.hints.dataModes.edit.placeholder', 'Ex.: Revise os dados antes de salvar.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.view.label', 'Visualizar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.view\"\n (ngModelChange)=\"updateDirtyState('hints-data-view')\" [placeholder]=\"tx('config.hints.dataModes.view.placeholder', 'Ex.: Visualiza\u00E7\u00E3o somente leitura.')\" />\n </mat-form-field>\n </section>\n\n <section>\n <h4>{{ tx('config.hints.uiModes.title', 'Modos de UI') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.presentation.label', 'Apresenta\u00E7\u00E3o') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.presentation\"\n (ngModelChange)=\"updateDirtyState('hints-ui-presentation')\" [placeholder]=\"tx('config.hints.uiModes.presentation.placeholder', 'Ex.: Modo compacto para leitura r\u00E1pida.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.readonly.label', 'Leitura (readonly)') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.readonly\"\n (ngModelChange)=\"updateDirtyState('hints-ui-readonly')\" [placeholder]=\"tx('config.hints.uiModes.readonly.placeholder', 'Ex.: Campos bloqueados para edi\u00E7\u00E3o.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.disabled.label', 'Desabilitado') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.disabled\"\n (ngModelChange)=\"updateDirtyState('hints-ui-disabled')\" [placeholder]=\"tx('config.hints.uiModes.disabled.placeholder', 'Ex.: Fun\u00E7\u00E3o indispon\u00EDvel no momento.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.visible.label', 'Vis\u00EDvel') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.visible\"\n (ngModelChange)=\"updateDirtyState('hints-ui-visible')\" [placeholder]=\"tx('config.hints.uiModes.visible.placeholder', 'Ex.: Campo exibido conforme permiss\u00F5es.')\"></textarea>\n </mat-form-field>\n </section>\n </div>\n\n <section>\n <h4>{{ tx('config.helpPresentation.title', 'Apresenta\u00E7\u00E3o das ajudas dos campos') }}</h4>\n <p class=\"text-caption\">{{ tx('config.helpPresentation.description', 'Controle como hint/helpText dos campos aparece em formul\u00E1rios densos. Erros de valida\u00E7\u00E3o continuam inline.') }}</p>\n <div class=\"grid-3-cols\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.display.label', 'Exibi\u00E7\u00E3o') }}</mat-label>\n <mat-select [ngModel]=\"helpPresentationDraft.display\" (ngModelChange)=\"onHelpPresentationDisplayChange($event)\">\n <mat-option value=\"inline\">{{ tx('config.helpPresentation.display.inline', 'Inline') }}</mat-option>\n <mat-option value=\"popover\">{{ tx('config.helpPresentation.display.popover', '\u00CDcone de ajuda') }}</mat-option>\n <mat-option value=\"auto\">{{ tx('config.helpPresentation.display.auto', 'Autom\u00E1tica') }}</mat-option>\n <mat-option value=\"hidden\">{{ tx('config.helpPresentation.display.hidden', 'Oculta') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.inlineMaxLength.label', 'Limite inline') }}</mat-label>\n <input matInput type=\"number\" min=\"0\" [ngModel]=\"helpPresentationDraft.inlineMaxLength\"\n (ngModelChange)=\"onHelpPresentationInlineMaxLengthChange($event)\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.preferPopoverForControls.label', 'Preferir \u00EDcone em') }}</mat-label>\n <input matInput [ngModel]=\"getHelpPreferPopoverControlsText()\"\n (ngModelChange)=\"onHelpPreferPopoverControlsChange($event)\"\n [placeholder]=\"tx('config.helpPresentation.preferPopoverForControls.placeholder', 'toggle, checkbox, select')\" />\n </mat-form-field>\n </div>\n </section>\n\n <div class=\"actions-row\">\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"restoreHintsDefaults()\">\n <mat-icon>restore</mat-icon>\n {{ tx('config.hints.actions.restoreDefaults', 'Restaurar padr\u00F5es') }}\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('actions')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-acoes\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.actions.title', 'A\u00E7\u00F5es do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.actions.subtitle', 'Configure bot\u00F5es padr\u00E3o e a\u00E7\u00F5es customizadas.') }}</p>\n </div>\n </div>\n <praxis-actions-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-actions-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('rules')\">\n <div class=\"tab-content visual-builder-content\" data-testid=\"config-tab-panel-regras\">\n <div class=\"builder-header\">\n <div>\n <h3>{{ tx('config.rules.title', 'Regras visuais') }}</h3>\n <p class=\"text-caption\">{{ tx('config.rules.subtitle', 'Defina visibilidade, estilos e rea\u00E7\u00F5es baseadas em condi\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n @if (ruleDiagnostics.length) {\n <div class=\"rules-diagnostics\" data-testid=\"rules-diagnostics-panel\">\n <div class=\"rules-diagnostics__summary\">\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--total\">\n {{ tx('config.rules.summary.total', '{{count}} regras', { count: ruleDiagnosticsSummary.total }) }}\n </span>\n @if (ruleDiagnosticsSummary.invalid) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--error\">\n {{ tx('config.rules.summary.invalid', '{{count}} inv\u00E1lidas', { count: ruleDiagnosticsSummary.invalid }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.unsupported) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.unsupported', '{{count}} com propriedades rejeitadas', { count: ruleDiagnosticsSummary.unsupported }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.runtimeOnly) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.runtimeOnly', '{{count}} runtime only', { count: ruleDiagnosticsSummary.runtimeOnly }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.pendingReview) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.pendingReview', '{{count}} pendentes de revis\u00E3o', { count: ruleDiagnosticsSummary.pendingReview }) }}\n </span>\n }\n </div>\n <div class=\"rules-diagnostics__list\" [attr.aria-label]=\"tx('config.rules.diagnostics.ariaLabel', 'Diagn\u00F3stico das regras')\">\n @for (diagnostic of ruleDiagnostics; track diagnostic) {\n <article class=\"rules-diagnostics__item\"\n [class.rules-diagnostics__item--error]=\"getRuleStatusTone(diagnostic) === 'error'\"\n [class.rules-diagnostics__item--warn]=\"getRuleStatusTone(diagnostic) === 'warn'\">\n <div>\n <strong>{{ diagnostic.ruleName || diagnostic.ruleId }}</strong>\n <span>\n {{ tx('config.rules.diagnostics.targetConditionSummary', '{{targets}} alvo(s) \u00B7 {{conditions}} campo(s) na condi\u00E7\u00E3o', { targets: diagnostic.targetRefs.length, conditions: diagnostic.conditionRefs.length }) }}\n </span>\n @if (getRuleDiagnosticDetails(diagnostic).length) {\n <ul class=\"rules-diagnostics__details\">\n @for (detail of getRuleDiagnosticDetails(diagnostic); track detail) {\n <li>{{ detail }}</li>\n }\n </ul>\n }\n </div>\n <div class=\"rules-diagnostics__actions\">\n <span class=\"rules-diagnostics__status\">{{ getRuleStatusLabel(diagnostic) }}</span>\n @if (canApplyRulePropertyFix(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.fix.tooltip', 'Aplicar whitelist e saneamento de propriedades nesta regra')\"\n (click)=\"applyRulePropertyFix(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">auto_fix_high</mat-icon>\n {{ tx('config.rules.actions.fix', 'Corrigir') }}\n </button>\n }\n @if (diagnostic.status.includes('llm-generated-pending-review')) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [disabled]=\"!canAcceptPendingLlmRule(diagnostic)\"\n [matTooltip]=\"canAcceptPendingLlmRule(diagnostic) ? tx('config.rules.actions.accept.tooltip.ready', 'Aceitar sugest\u00E3o e atualizar estado visual') : tx('config.rules.actions.accept.tooltip.blocked', 'Corrija alvo, condi\u00E7\u00E3o e propriedades antes de aceitar')\"\n (click)=\"acceptPendingLlmRule(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.rules.actions.accept', 'Aceitar') }}\n </button>\n }\n @if (canOpenRuleJsonReview(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.reviewJson.tooltip', 'Abrir a aba JSON para revisar esta regra sem convers\u00E3o visual')\"\n (click)=\"openRuleJsonReview(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">data_object</mat-icon>\n {{ tx('config.rules.actions.reviewJson', 'Ver JSON') }}\n </button>\n }\n </div>\n </article>\n }\n </div>\n </div>\n } @else {\n <div class=\"rules-diagnostics rules-diagnostics--empty\" data-testid=\"rules-diagnostics-empty\">\n {{ tx('config.rules.empty', 'Nenhuma regra definida ainda. Crie uma regra para ver alvos, condi\u00E7\u00E3o, propriedades e compatibilidade do builder.') }}\n </div>\n }\n <praxis-visual-builder [config]=\"ruleBuilderConfig\" [initialRules]=\"ruleBuilderState\"\n (rulesChanged)=\"onRulesChanged($event)\"></praxis-visual-builder>\n <praxis-rule-properties-panel\n [rules]=\"currentRules\"\n [visualBlockNodes]=\"visualBlockNodeOptions\"\n (rulesChange)=\"onRulePropertiesChanged($event)\"\n ></praxis-rule-properties-panel>\n <mat-card class=\"command-rules-card\" data-testid=\"form-command-rules-editor\">\n <mat-card-title>{{ tx('config.commandRules.title', 'Comandos condicionais') }}</mat-card-title>\n <mat-card-subtitle>{{ tx('config.commandRules.subtitle', 'Execute a\u00E7\u00F5es globais quando uma condi\u00E7\u00E3o do formul\u00E1rio for satisfeita.') }}</mat-card-subtitle>\n <mat-card-content>\n <div class=\"command-rules-grid\">\n <div class=\"command-rules-toolbar\">\n <mat-form-field appearance=\"fill\" class=\"command-rules-select\">\n <mat-label>{{ tx('config.commandRules.command.label', 'Comando') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedCommandRuleId\" (selectionChange)=\"onCommandRuleSelectionChange()\">\n @for (rule of commandRules; track rule) {\n <mat-option [value]=\"rule.id\">\n {{ rule.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <button mat-stroked-button type=\"button\" (click)=\"addCommandRule()\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n {{ tx('config.commandRules.actions.add', 'Adicionar') }}\n </button>\n <button mat-stroked-button color=\"warn\" type=\"button\" (click)=\"deleteCommandRule()\" [disabled]=\"!selectedCommandRuleId\">\n <mat-icon aria-hidden=\"true\">delete</mat-icon>\n {{ tx('config.commandRules.actions.remove', 'Remover') }}\n </button>\n </div>\n\n @if (selectedCommandRuleId) {\n <div class=\"command-rule-condition-builder command-rules-full\">\n <praxis-visual-builder\n mode=\"condition\"\n [config]=\"ruleBuilderConfig\"\n [initialCondition]=\"commandRuleCondition\"\n (conditionChanged)=\"onCommandConditionChanged($event)\"\n ></praxis-visual-builder>\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.conditionJson.label', 'Condi\u00E7\u00E3o JSON Logic') }}</mat-label>\n <textarea\n matInput\n rows=\"5\"\n [(ngModel)]=\"commandRuleConditionJson\"\n [attr.aria-label]=\"tx('config.commandRules.conditionJson.ariaLabel', 'Condi\u00E7\u00E3o JSON Logic do comando condicional')\"\n ></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.globalAction.label', 'A\u00E7\u00E3o global') }}</mat-label>\n <mat-select [(ngModel)]=\"commandRuleActionId\" (selectionChange)=\"onCommandActionChange()\">\n @for (action of globalActionCatalog; track action) {\n <mat-option [value]=\"action.id\">\n {{ action.label || action.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.distinctBy.label', 'distinctBy') }}</mat-label>\n <input matInput [(ngModel)]=\"commandRuleDistinctBy\" [placeholder]=\"tx('config.commandRules.distinctBy.placeholder', 'ex.: idade')\" />\n </mat-form-field>\n\n @if (commandRuleActionSchema; as actionSchema) {\n <div\n class=\"command-rules-payload-fields command-rules-full\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.structuredPayload.title', 'Payload estruturado') }}</div>\n @if (actionSchema.editorMode !== 'surface-open') {\n @for (field of actionSchema.fields; track field) {\n @if (shouldShowCommandActionField(field)) {\n @if (field.type === 'toggle') {\n <mat-slide-toggle\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n >\n {{ field.label }}\n </mat-slide-toggle>\n } @else {\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ field.label }}</mat-label>\n @if (field.type === 'textarea' || field.type === 'json') {\n <textarea\n matInput\n [rows]=\"field.rows || (field.type === 'json' ? 3 : 2)\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || (field.type === 'json' ? '{ }' : '')\"\n [required]=\"isCommandActionFieldRequired(field)\"\n ></textarea>\n } @else {\n @if (field.type === 'select') {\n <mat-select\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [required]=\"isCommandActionFieldRequired(field)\"\n >\n @for (option of field.options || []; track option) {\n <mat-option [value]=\"option.value\">\n {{ option.label }}\n </mat-option>\n }\n </mat-select>\n } @else {\n <input\n matInput\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || ''\"\n [required]=\"isCommandActionFieldRequired(field)\"\n />\n }\n }\n @if (field.hint) {\n <mat-hint>{{ field.hint }}</mat-hint>\n }\n @if (hasCommandActionFieldError(field.key)) {\n <mat-error>\n {{ getCommandActionFieldError(field.key) }}\n </mat-error>\n }\n @if (!hasCommandActionFieldError(field.key) && isCommandActionFieldMissing(field)) {\n <mat-error>\n {{ tx('config.commandRules.validation.requiredField', 'Campo obrigat\u00F3rio.') }}\n </mat-error>\n }\n </mat-form-field>\n }\n }\n }\n } @else {\n <praxis-surface-open-action-editor\n class=\"command-rules-surface-editor\"\n data-testid=\"form-command-rule-surface-open-editor\"\n [value]=\"commandRuleSurfaceOpenPayload\"\n hostKind=\"dynamic-form\"\n (valueChange)=\"onCommandSurfaceOpenPayloadChange($event)\"\n ></praxis-surface-open-action-editor>\n }\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.advancedPayload.label', 'Payload JSON avan\u00E7ado') }}</mat-label>\n <textarea\n matInput\n rows=\"4\"\n [(ngModel)]=\"commandRulePayloadJson\"\n [attr.aria-label]=\"tx('config.commandRules.advancedPayload.ariaLabel', 'Payload JSON da a\u00E7\u00E3o global')\"\n ></textarea>\n </mat-form-field>\n\n <div class=\"command-rules-options\">\n <mat-slide-toggle [(ngModel)]=\"commandRuleDistinct\">{{ tx('config.commandRules.options.distinct', 'Evitar repeti\u00E7\u00E3o enquanto a condi\u00E7\u00E3o permanecer verdadeira') }}</mat-slide-toggle>\n <mat-slide-toggle [(ngModel)]=\"commandRuleRunOnInitialEvaluation\">{{ tx('config.commandRules.options.runOnInitialEvaluation', 'Executar tamb\u00E9m na avalia\u00E7\u00E3o inicial') }}</mat-slide-toggle>\n </div>\n\n @if (commandRuleAuthoringError) {\n <div class=\"preview-error command-rules-full\">\n <mat-icon aria-hidden=\"true\">warning</mat-icon>\n <span>{{ commandRuleAuthoringError }}</span>\n </div>\n }\n\n <div\n class=\"command-rule-preview command-rules-full\"\n [class.command-rule-preview--invalid]=\"commandRulePreview.state === 'invalid'\"\n data-testid=\"command-rule-preview\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.preview.title', 'Preview do comando') }}</div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.mode', 'Modo') }}</span>\n <strong>{{ commandRulePreview.executionMode }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.action', 'A\u00E7\u00E3o') }}</span>\n <strong>{{ commandRulePreview.actionId || '\u2014' }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.policy', 'Policy') }}</span>\n <code>{{ commandRulePreview.policy | json }}</code>\n </div>\n @if (commandRulePreview.diagnostics.length) {\n <div class=\"command-rule-preview__diagnostics\">\n <mat-icon aria-hidden=\"true\">{{ commandRulePreview.state === 'invalid' ? 'warning' : 'visibility' }}</mat-icon>\n <span>{{ commandRulePreview.diagnostics[0] }}</span>\n </div>\n }\n </div>\n\n <div class=\"command-rules-actions\">\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"applyCommandRule()\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.commandRules.actions.apply', 'Aplicar comando') }}\n </button>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('cascades')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-cascatas\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.cascades.title', 'Depend\u00EAncias entre campos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.cascades.subtitle', 'Configure cascatas e carregamento entre campos.') }}</p>\n </div>\n </div>\n <praxis-cascade-manager-tab [fields]=\"editedConfig.fieldMetadata || []\"\n (apply)=\"onCascadeApply($event)\"></praxis-cascade-manager-tab>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('messages')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-mensagens\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.messages.title', 'Mensagens e feedback') }}</h3>\n <p class=\"text-caption\">{{ tx('config.messages.subtitle', 'Padronize textos de sucesso, erro e confirma\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n <praxis-messages-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-messages-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('navigation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-navegacao\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.navigation.title', 'Navega\u00E7\u00E3o de retorno') }}</h3>\n <p class=\"text-caption\">{{ tx('config.navigation.subtitle', 'Defina o comportamento do bot\u00E3o Voltar em fluxos CRUD.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.navigation.returnTo.label', 'Rota de retorno') }}</mat-label>\n <input matInput id=\"returnTo\" [(ngModel)]=\"backConfig!.returnTo\" (ngModelChange)=\"onBackConfigChange()\" [placeholder]=\"tx('config.navigation.returnTo.placeholder', '/funcionarios')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"backConfig!.confirmOnDirty\" (ngModelChange)=\"onBackConfigChange()\">\n {{ tx('config.navigation.confirmOnDirty.label', 'Confirmar ao sair com altera\u00E7\u00F5es') }}\n </mat-slide-toggle>\n </div>\n <div class=\"block-status\" [class.block-status--implicit]=\"!isBackConfigBlockPersisted()\">\n <strong>{{ tx('config.navigation.backConfig.label', 'Back Config') }}</strong>\n @if (isBackConfigBlockPersisted()) {\n <span>{{ tx('config.navigation.backConfig.persisted', '`contextSnapshot.backConfig` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.navigation.backConfig.implicit', 'Bloco ausente no documento can\u00F4nico. Os valores exibidos s\u00E3o fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.navigation.note.label', 'Observa\u00E7\u00E3o:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.navigation.note.tooltip', 'Afeta o fluxo de navega\u00E7\u00E3o do CRUD e pode ser sobreposto por metadados do recurso.')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('json')\">\n <div class=\"tab-content json-tab-content\" data-testid=\"config-tab-panel-json\">\n <mat-card class=\"section-card section-card--json\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.json.title', 'Configura\u00E7\u00E3o JSON') }}</h3>\n <p class=\"text-caption\">{{ tx('config.json.subtitle', 'Edi\u00E7\u00E3o avan\u00E7ada do documento can\u00F4nico de autoria do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <form-json-config-editor [document]=\"jsonDocument\" (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\" (editorEvent)=\"onJsonEditorEvent($event)\">\n </form-json-config-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n</mat-tab-group>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-width:0}.mobile-tab-selector{display:none;flex:0 0 auto;padding:8px 16px 0;background:var(--md-sys-color-surface)}.mobile-tab-selector__field{width:100%}.config-tabs{flex:1 1 auto;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs{display:flex;flex-direction:column}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-wrapper{flex:1;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-content{height:100%;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;padding:0!important}.tab-content{padding:16px 20px 20px;flex:1;min-width:0;box-sizing:border-box}.json-tab-content{min-width:0;padding:12px 16px 16px}.section-card--json{display:flex;flex:1;min-height:calc(100vh - 180px);border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.section-card--json>mat-card-content{display:flex;flex:1;min-width:0;min-height:0;flex-direction:column}.section-card--json form-json-config-editor{display:block;flex:1;min-width:0;min-height:0}.form-row{display:block;margin-bottom:12px}.form-grid{display:grid;gap:12px}.section-help{display:inline-flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:12px}.section-help__label{font-weight:500}.grid-2-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}.grid-2-cols--compact{gap:12px}.w-100{width:100%}.visual-builder-content{padding:0!important;height:100%;min-width:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:16px}.visual-builder-content>praxis-visual-builder{flex:0 0 auto;min-width:0;min-height:clamp(360px,48vh,560px)}.visual-builder-content>praxis-rule-properties-panel{flex:0 0 auto;display:block;min-width:0;padding:0 16px 24px;box-sizing:border-box}.rules-diagnostics{flex:0 0 auto;display:grid;gap:10px;padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.rules-diagnostics--empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.rules-diagnostics__summary,.rules-diagnostics__list{display:flex;flex-wrap:wrap;gap:8px}.rules-diagnostics__pill{display:inline-flex;align-items:center;min-height:24px;padding:3px 9px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:12px;font-weight:600}.rules-diagnostics__pill--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container) 72%,transparent);color:var(--md-sys-color-on-tertiary-container)}.rules-diagnostics__pill--error{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.rules-diagnostics__item{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;min-width:min(100%,280px);padding:8px 10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container)}.rules-diagnostics__item>div{display:grid;gap:2px;min-width:0}.rules-diagnostics__item strong{color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rules-diagnostics__item span{color:var(--md-sys-color-on-surface-variant);font-size:11px}.rules-diagnostics__actions{flex:0 0 auto;display:flex;align-items:center;gap:8px}.rules-diagnostics__details{display:grid;gap:2px;margin:4px 0 0;padding-left:16px;color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35}.rules-diagnostics__details li{overflow-wrap:anywhere}.rules-diagnostics__item--warn{border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 52%,var(--md-sys-color-outline-variant))}.rules-diagnostics__item--error{border-color:var(--md-sys-color-error)}.rules-diagnostics__status{font-weight:600;margin-top:1px}.rules-diagnostics__action{min-width:0;height:28px;padding:0 10px;border-radius:999px;font-size:12px;line-height:1}.rules-diagnostics__action mat-icon{width:16px;height:16px;margin:0 4px 0 0;font-size:16px}.json-field{width:100%}.presentation-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:20px;align-items:start}.presentation-controls{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px 18px}.control{display:flex;flex-direction:column}.control-span{grid-column:1/-1}.block-status{grid-column:1/-1;display:flex;gap:8px;align-items:flex-start;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 35%,transparent);color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.45}.block-status strong{min-width:112px;font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant)}.block-status--implicit{background:color-mix(in srgb,var(--md-sys-color-surface-variant) 42%,transparent);border:1px dashed var(--md-sys-color-outline)}.block-status--readonly{margin-bottom:12px}.block-status code{font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:11px}.control__label{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:6px}.toggle-group{max-width:100%;flex-wrap:wrap}.control--inline{grid-column:1/-1;display:flex;gap:16px;align-items:center}.presentation-preview{min-width:0;order:-1}.preview-card{border:1px solid var(--md-sys-color-outline);border-radius:12px;padding:14px;background:var(--md-sys-color-surface-container)}.preview-row{display:flex;gap:8px;padding:6px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.preview-row:last-child{border-bottom:none}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.presentation-preview .praxis-presentation__label{color:var(--md-sys-color-on-surface-variant);font-size:var(--pfx-pres-label-size, 12px)}.presentation-preview .praxis-presentation__value{min-width:0;overflow-wrap:anywhere;font-size:var(--pfx-pres-value-size, 16px);color:var(--md-sys-color-on-surface)}.presentation-preview .presentation-mode.pres-density-cozy .preview-row{padding:6px 0}.presentation-preview .presentation-mode.pres-density-compact .preview-row,.presentation-preview .presentation-mode.pres-compact .preview-row{padding:2px 0}.presentation-preview .presentation-mode.pres-label-left .preview-row{display:grid;grid-template-columns:var(--pfx-pres-label-width, 140px) 1fr;align-items:baseline;column-gap:10px}.presentation-preview .presentation-mode.pres-label-left .praxis-presentation__label{margin:0;text-align:var(--pfx-pres-label-align, start)}.presentation-preview .presentation-mode .praxis-presentation__value{text-align:var(--pfx-pres-value-align, start)}.presentation-preview h4{margin:0 0 8px;color:var(--md-sys-color-on-surface);font-size:1rem}.section-card{border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-level1, none)}.section-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.tab-content--dense{padding:12px 16px 16px}.tab-content--dense .section-header,.tab-content--dense .form-row{margin-bottom:8px}.section-header h3{margin:0;font-size:1.05rem;color:var(--md-sys-color-on-surface)}.text-caption{margin:6px 0 0;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.section-header--compact{margin-bottom:8px}.section-body{display:block}.section-body--flex{flex:1;min-height:0;display:flex;flex-direction:column}.builder-header{padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.builder-header h3{margin:0;font-size:1rem;color:var(--md-sys-color-on-surface)}.hint{margin:8px 0 0;padding:10px 12px;border-radius:10px;border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface-variant)}.meta-card{display:grid;gap:6px;padding:10px 12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.meta-row{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.meta-row strong{color:var(--md-sys-color-on-surface);font-weight:600}.runtime-contract-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.runtime-contract-field{display:grid;gap:6px;padding:12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.runtime-contract-label{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.runtime-contract-code{display:block;font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:12px;line-height:1.45;color:var(--md-sys-color-on-surface);word-break:break-word;white-space:normal}.command-rules-card{margin:16px;min-width:0;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container)}.command-rules-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:12px;align-items:start;min-width:0}.command-rules-toolbar,.command-rules-options,.command-rules-actions{grid-column:1/-1;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.command-rules-select{min-width:min(320px,100%)}.command-rules-full{grid-column:1/-1}.command-rule-condition-builder{min-height:420px;overflow:hidden;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-payload-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px;min-width:0;padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-section-title{grid-column:1/-1;font-size:12px;font-weight:600;color:var(--md-sys-color-on-surface-variant);text-transform:uppercase}.command-rules-surface-editor{grid-column:1/-1}.command-rule-preview{display:grid;gap:8px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.command-rule-preview--invalid{border-color:var(--md-sys-color-error)}.command-rule-preview__row{display:grid;grid-template-columns:minmax(96px,.35fr) minmax(0,1fr);gap:8px;align-items:start;min-width:0}.command-rule-preview__row span{color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:600}.command-rule-preview__row strong,.command-rule-preview__row code{min-width:0;overflow-wrap:anywhere}.command-rule-preview__diagnostics{display:flex;gap:8px;align-items:flex-start;color:var(--md-sys-color-on-surface-variant)}@media(max-width:768px){.mobile-tab-selector{display:block}::ng-deep .mat-mdc-tab-group.config-tabs>.mat-mdc-tab-header{display:none}.tab-content{padding:12px}.json-tab-content{padding:8px}.section-card--json{min-height:auto}}.form-modes{display:flex;flex-direction:column;align-items:flex-start;gap:16px}.form-modes mat-button-toggle-group{max-width:100%;flex-wrap:wrap}.display-result{margin:0;padding-block:12px;color:var(--md-sys-color-on-surface);font:var(--md-sys-typescale-body-medium)}.presentation-preview .presentation-mode.pres-label-above .preview-row{flex-direction:column;gap:4px}.presentation-controls,.control{min-width:0}.block-status{flex-wrap:wrap}:host{container-type:inline-size}@container (min-width: 900px){.presentation-layout{grid-template-columns:minmax(0,1fr) minmax(280px,.8fr)}.presentation-preview{order:1;position:sticky;top:16px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$3.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i6$3.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i6$3.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i7$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i7$1.MatCardContent, selector: "mat-card-content" }, { kind: "directive", type: i7$1.MatCardSubtitle, selector: "mat-card-subtitle, [mat-card-subtitle], [matCardSubtitle]" }, { kind: "directive", type: i7$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i5$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i5$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i5$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i6$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: i6$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$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: MatCheckboxModule }, { kind: "component", type: i12.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: MatSlideToggleModule }, { kind: "component", type: i5$2.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i7$2.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i7$2.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisIconButtonComponent, selector: "button[praxisIconButton]", inputs: ["praxisIconButton", "size", "appearance", "presentation", "pressed", "busy"] }, { kind: "component", type: JsonConfigEditorComponent, selector: "form-json-config-editor", inputs: ["config", "document"], outputs: ["configChange", "documentChange", "validationChange", "editorEvent"] }, { kind: "component", type: LayoutEditorComponent, selector: "praxis-layout-editor", inputs: ["config"], outputs: ["configChange", "select"] }, { kind: "component", type: BehaviorEditorComponent, selector: "praxis-behavior-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: ActionsEditorComponent$1, selector: "praxis-actions-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: MessagesEditorComponent, selector: "praxis-messages-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: HooksEditorComponent, selector: "praxis-hooks-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: RulePropertiesPanelComponent, selector: "praxis-rule-properties-panel", inputs: ["rules", "visualBlockNodes"], outputs: ["rulesChange"] }, { kind: "component", type: PraxisVisualBuilder, selector: "praxis-visual-builder", inputs: ["mode", "config", "initialRules", "initialCondition"], outputs: ["rulesChanged", "conditionChanged", "exportRequested", "importRequested"] }, { kind: "component", type: CascadeManagerTabComponent, selector: "praxis-cascade-manager-tab", inputs: ["fields", "connections"], outputs: ["apply", "cancel"] }, { kind: "component", type: SurfaceOpenActionEditorComponent, selector: "praxis-surface-open-action-editor", inputs: ["value", "hostKind"], outputs: ["valueChange"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }] });
31495
31603
  }
31496
31604
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicFormConfigEditor, decorators: [{
31497
31605
  type: Component,
@@ -31520,7 +31628,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
31520
31628
  PraxisVisualBuilder,
31521
31629
  CascadeManagerTabComponent,
31522
31630
  SurfaceOpenActionEditorComponent,
31523
- ], providers: [FormConfigService], template: "<div class=\"mobile-tab-selector\">\n <mat-form-field appearance=\"outline\" class=\"mobile-tab-selector__field\">\n <mat-label>{{ tx('config.tabs.mobileLabel', 'Se\u00E7\u00E3o do editor') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedConfigTabIndex\" data-testid=\"dynamic-form-config-editor-mobile-tabs\">\n @for (tab of configTabOptions; track tab.key) {\n <mat-option [value]=\"tab.index\">{{ tab.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n\n<mat-tab-group class=\"config-tabs\" data-testid=\"dynamic-form-config-editor-tabs\" [(selectedIndex)]=\"selectedConfigTabIndex\">\n <mat-tab [label]=\"configTabLabel('general')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-geral\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.title', 'Dados do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.general.subtitle', 'Defina o modo de dados e o contexto de edi\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.general.inputMode.label', 'Modo de dados') }}</mat-label>\n <mat-select [(ngModel)]=\"inputMode\" (ngModelChange)=\"onInputModeChange()\">\n <mat-option value=\"create\">{{ tx('config.general.inputMode.create', 'create') }}</mat-option>\n <mat-option value=\"edit\">{{ tx('config.general.inputMode.edit', 'edit') }}</mat-option>\n <mat-option value=\"view\">{{ tx('config.general.inputMode.view', 'view') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"block-status\" [class.block-status--implicit]=\"!isBindingsBlockPersisted()\">\n <strong>{{ tx('config.general.bindings.label', 'Bindings') }}</strong>\n @if (isBindingsBlockPersisted()) {\n <span>{{ tx('config.general.bindings.persisted', '`bindings.mode` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.general.bindings.implicit', 'Bloco ausente no documento can\u00F4nico. O valor exibido \u00E9 fallback visual e n\u00E3o ser\u00E1 salvo at\u00E9 voc\u00EA editar este campo.') }}\n }\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.common.understand', 'Entenda:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.general.inputMode.tooltip', 'O mode controla o fluxo (create/edit/view). enableCustomization s\u00F3 libera edi\u00E7\u00E3o do layout e n\u00E3o altera o mode.')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n\n @if (hasResolvedRuntimeContract()) {\n <mat-card\n class=\"section-card\"\n data-testid=\"config-tab-runtime-contract\"\n >\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.runtimeContract.title', 'Contrato Runtime Resolvido') }}</h3>\n <p class=\"text-caption\">\n {{ tx('config.general.runtimeContract.subtitle', 'Visualiza\u00E7\u00E3o somente leitura do contrato backend resolvido pelo host atual.') }}\n </p>\n </div>\n </div>\n <div class=\"block-status block-status--readonly\">\n <strong>{{ tx('config.general.runtimeContract.runtimeLabel', 'Runtime') }}</strong>\n <span>\n {{ tx('config.general.runtimeContract.readonly', 'Esses valores v\u00EAm do host/runtime atual e n\u00E3o s\u00E3o persistidos em `bindings` nem em `contextSnapshot`.') }}\n </span>\n </div>\n <div class=\"runtime-contract-grid\">\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaUrl', 'Schema URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.schemaUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaSource', 'Origem do schema') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.schemaSource) }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitMethod', 'Submit method') }}</span>\n <strong>{{ runtimeContract?.submitMethod || '\u2014' }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitUrl', 'Submit URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.submitUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitSource', 'Origem do submit') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.submitSource) }}</strong>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n }\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('schema')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-schema\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.schema.title', 'Valida\u00E7\u00E3o de schema') }}</h3>\n <p class=\"text-caption\">{{ tx('config.schema.subtitle', 'Controle avisos quando o schema do servidor mudar.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.notify.label', 'Notificar quando desatualizado') }}</mat-label>\n <mat-select [(ngModel)]=\"schemaPrefs.notifyIfOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-notify')\">\n <mat-option value=\"both\">{{ tx('config.schema.notify.both', 'Banner + Snackbar') }}</mat-option>\n <mat-option value=\"inline\">{{ tx('config.schema.notify.inline', 'Somente Banner') }}</mat-option>\n <mat-option value=\"snackbar\">{{ tx('config.schema.notify.snackbar', 'Somente Snackbar') }}</mat-option>\n <mat-option value=\"none\">{{ tx('config.schema.notify.none', 'Nenhum') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.snooze.label', 'Intervalo de sil\u00EAncio (ms)') }}</mat-label>\n <input matInput type=\"number\" [(ngModel)]=\"schemaPrefs.snoozeMs\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-snooze')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"schemaPrefs.autoOpenSettingsOnOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-auto-open')\">\n {{ tx('config.schema.autoOpenSettings', 'Abrir configura\u00E7\u00F5es automaticamente') }}\n </mat-slide-toggle>\n </div>\n @if (serverMeta) {\n <div class=\"form-row\">\n <div class=\"meta-card\">\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.serverHash', 'Server hash') }}</span>\n <strong>{{ serverMeta.serverHash || '\u2014' }}</strong>\n </div>\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.lastVerifiedAt', '\u00DAltima verifica\u00E7\u00E3o') }}</span>\n <strong>{{ serverMeta.lastVerifiedAt || '\u2014' }}</strong>\n </div>\n </div>\n </div>\n }\n <div class=\"block-status\" [class.block-status--implicit]=\"!isSchemaPrefsBlockPersisted()\">\n <strong>{{ tx('config.schema.prefs.label', 'Schema Prefs') }}</strong>\n @if (isSchemaPrefsBlockPersisted()) {\n <span>{{ tx('config.schema.prefs.persisted', '`contextSnapshot.schemaPrefs` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.schema.prefs.implicit', 'Bloco ausente no documento can\u00F4nico. Os controles exibem fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('layout')\">\n <div class=\"tab-content tab-content--full\" data-testid=\"config-tab-panel-layout\">\n <div class=\"section-header section-header--compact\">\n <div>\n <h3>{{ tx('config.layout.title', 'Layout do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.layout.subtitle', 'Organize se\u00E7\u00F5es, linhas e campos com drag & drop.') }}</p>\n </div>\n </div>\n <div class=\"section-body section-body--flex\">\n <praxis-layout-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"\n (select)=\"onLayoutSelect($event)\"></praxis-layout-editor>\n </div>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hooks')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-hooks\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hooks.title', 'Hooks de ciclo de vida') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hooks.subtitle', 'Automatize a\u00E7\u00F5es nos eventos do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-hooks-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-hooks-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n @if (isPresentationMode) {\n <mat-tab [label]=\"configTabLabel('presentation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-presentation\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.presentation.title', 'Modo Apresenta\u00E7\u00E3o') }}</h3>\n <p class=\"text-caption\">{{ tx('config.presentation.subtitle', 'Configura\u00E7\u00F5es de exibi\u00E7\u00E3o aplicadas somente ao modo apresenta\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <div class=\"presentation-layout\">\n <div class=\"presentation-controls\">\n <div class=\"block-status control-span\" [class.block-status--implicit]=\"!isPresentationBlockPersisted()\">\n <strong>{{ tx('config.presentation.block.label', 'Presentation') }}</strong>\n @if (isPresentationBlockPersisted()) {\n <span>{{ tx('config.presentation.block.persisted', '`contextSnapshot.presentation` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.presentation.block.implicit', 'Bloco ausente no documento can\u00F4nico. A pr\u00E9-visualiza\u00E7\u00E3o usa fallback local e n\u00E3o ser\u00E1 salva at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelPosition.label', 'Posi\u00E7\u00E3o do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelPosition\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-position')\" [attr.aria-label]=\"tx('config.presentation.labelPosition.ariaLabel', 'Posi\u00E7\u00E3o do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"above\">\n <mat-icon>view_stream</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.above', 'Acima') }}</span>\n </mat-button-toggle>\n <mat-button-toggle value=\"left\">\n <mat-icon>view_column</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.left', '\u00C0 esquerda') }}</span>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.density.label', 'Densidade') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.density\" (ngModelChange)=\"onPresentationPrefsChange('presentation-density')\" [attr.aria-label]=\"tx('config.presentation.density.ariaLabel', 'Densidade')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"comfortable\">{{ tx('config.presentation.density.comfortable', 'Confort\u00E1vel') }}</mat-button-toggle>\n <mat-button-toggle value=\"cozy\">{{ tx('config.presentation.density.cozy', 'Intermedi\u00E1ria') }}</mat-button-toggle>\n <mat-button-toggle value=\"compact\">{{ tx('config.presentation.density.compact', 'Compacta') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelAlign.label', 'Alinhamento do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-align')\" [attr.aria-label]=\"tx('config.presentation.labelAlign.ariaLabel', 'Alinhamento do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.valueAlign.label', 'Alinhamento do valor') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.valueAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-align')\" [attr.aria-label]=\"tx('config.presentation.valueAlign.ariaLabel', 'Alinhamento do valor')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelFontSize.label', 'Tamanho do r\u00F3tulo') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" [(ngModel)]=\"presentationPrefs.labelFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-font-size')\"\n [placeholder]=\"tx('config.presentation.labelFontSize.placeholder', 'ex.: 12')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.valueFontSize.label', 'Tamanho do valor') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" [(ngModel)]=\"presentationPrefs.valueFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-font-size')\"\n [placeholder]=\"tx('config.presentation.valueFontSize.placeholder', 'ex.: 16')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelWidth.label', 'Largura do r\u00F3tulo (label \u00E0 esquerda)') }}</mat-label>\n <input matInput type=\"number\" min=\"60\" [(ngModel)]=\"presentationPrefs.labelWidth\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-width')\"\n [placeholder]=\"tx('config.presentation.labelWidth.placeholder', 'ex.: 140')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control control--inline\">\n <mat-slide-toggle [(ngModel)]=\"presentationPrefs.compact\" (ngModelChange)=\"onPresentationPrefsChange('presentation-compact')\">\n {{ tx('config.presentation.options.compactMode', 'Modo compacto') }}\n </mat-slide-toggle>\n <mat-checkbox [(ngModel)]=\"truncatePreview\">\n {{ tx('config.presentation.options.truncateValues', 'Truncar valores') }}\n </mat-checkbox>\n </div>\n </div>\n <div class=\"presentation-preview\">\n <h4>{{ tx('config.presentation.preview.title', 'Pr\u00E9-visualiza\u00E7\u00E3o') }}</h4>\n <div class=\"preview-card\">\n <div class=\"praxis-dynamic-form presentation-mode\" [ngClass]=\"{\n 'pres-compact': !!presentationPrefs.compact,\n 'pres-label-left': presentationPrefs.labelPosition === 'left',\n 'pres-label-above': presentationPrefs.labelPosition === 'above',\n 'pres-density-compact': presentationPrefs.density === 'compact',\n 'pres-density-cozy': presentationPrefs.density === 'cozy'\n }\" [style.--pfx-pres-label-size]=\"(presentationPrefs.labelFontSize || 12) + 'px'\"\n [style.--pfx-pres-value-size]=\"(presentationPrefs.valueFontSize || 16) + 'px'\"\n [style.--pfx-pres-label-width]=\"(presentationPrefs.labelWidth || 140) + 'px'\"\n [style.--pfx-pres-label-align]=\"presentationPrefs.labelAlign || 'start'\"\n [style.--pfx-pres-value-align]=\"presentationPrefs.valueAlign || 'start'\">\n @for (item of previewItems; track item) {\n <div class=\"preview-row\">\n <span class=\"praxis-presentation__label\">{{ item.label }}</span>\n <span class=\"praxis-presentation__value\" [title]=\"truncatePreview ? item.value : null\"\n [style.maxWidth]=\"truncatePreview ? '280px' : null\"\n [style.overflow]=\"truncatePreview ? 'hidden' : null\"\n [style.textOverflow]=\"truncatePreview ? 'ellipsis' : null\"\n [style.whiteSpace]=\"truncatePreview ? 'nowrap' : 'normal'\">\n {{ item.value }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.common.understand', 'Entenda:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.presentation.help.tooltip', 'Ajustes aplicam somente ao Modo Apresenta\u00E7\u00E3o e s\u00E3o salvos por formul\u00E1rio (via CSS/Classes).')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n }\n <mat-tab [label]=\"configTabLabel('behavior')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-comportamento\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.behavior.title', 'Comportamento') }}</h3>\n <p class=\"text-caption\">{{ tx('config.behavior.subtitle', 'Ajuste valida\u00E7\u00F5es e respostas do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-behavior-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-behavior-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hints')\">\n <div class=\"tab-content tab-content--dense\" data-testid=\"config-tab-panel-hints\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hints.title', 'Dicas dos modos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hints.subtitle', 'Personalize textos de apoio para modos de dados e estados de UI.') }}</p>\n </div>\n </div>\n <p class=\"text-caption\">{{ tx('config.hints.description', 'Personalize os textos usados como tooltip/hint para modos de dados e modos globais de UI.') }}</p>\n\n <div class=\"grid-2-cols grid-2-cols--compact\">\n <section>\n <h4>{{ tx('config.hints.dataModes.title', 'Modos de dados') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.create.label', 'Criar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.create\"\n (ngModelChange)=\"updateDirtyState('hints-data-create')\" [placeholder]=\"tx('config.hints.dataModes.create.placeholder', 'Ex.: Preencha os campos obrigat\u00F3rios.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.edit.label', 'Editar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.edit\"\n (ngModelChange)=\"updateDirtyState('hints-data-edit')\" [placeholder]=\"tx('config.hints.dataModes.edit.placeholder', 'Ex.: Revise os dados antes de salvar.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.view.label', 'Visualizar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.view\"\n (ngModelChange)=\"updateDirtyState('hints-data-view')\" [placeholder]=\"tx('config.hints.dataModes.view.placeholder', 'Ex.: Visualiza\u00E7\u00E3o somente leitura.')\" />\n </mat-form-field>\n </section>\n\n <section>\n <h4>{{ tx('config.hints.uiModes.title', 'Modos de UI') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.presentation.label', 'Apresenta\u00E7\u00E3o') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.presentation\"\n (ngModelChange)=\"updateDirtyState('hints-ui-presentation')\" [placeholder]=\"tx('config.hints.uiModes.presentation.placeholder', 'Ex.: Modo compacto para leitura r\u00E1pida.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.readonly.label', 'Leitura (readonly)') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.readonly\"\n (ngModelChange)=\"updateDirtyState('hints-ui-readonly')\" [placeholder]=\"tx('config.hints.uiModes.readonly.placeholder', 'Ex.: Campos bloqueados para edi\u00E7\u00E3o.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.disabled.label', 'Desabilitado') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.disabled\"\n (ngModelChange)=\"updateDirtyState('hints-ui-disabled')\" [placeholder]=\"tx('config.hints.uiModes.disabled.placeholder', 'Ex.: Fun\u00E7\u00E3o indispon\u00EDvel no momento.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.visible.label', 'Vis\u00EDvel') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.visible\"\n (ngModelChange)=\"updateDirtyState('hints-ui-visible')\" [placeholder]=\"tx('config.hints.uiModes.visible.placeholder', 'Ex.: Campo exibido conforme permiss\u00F5es.')\"></textarea>\n </mat-form-field>\n </section>\n </div>\n\n <section>\n <h4>{{ tx('config.helpPresentation.title', 'Apresenta\u00E7\u00E3o das ajudas dos campos') }}</h4>\n <p class=\"text-caption\">{{ tx('config.helpPresentation.description', 'Controle como hint/helpText dos campos aparece em formul\u00E1rios densos. Erros de valida\u00E7\u00E3o continuam inline.') }}</p>\n <div class=\"grid-3-cols\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.display.label', 'Exibi\u00E7\u00E3o') }}</mat-label>\n <mat-select [ngModel]=\"helpPresentationDraft.display\" (ngModelChange)=\"onHelpPresentationDisplayChange($event)\">\n <mat-option value=\"inline\">{{ tx('config.helpPresentation.display.inline', 'Inline') }}</mat-option>\n <mat-option value=\"popover\">{{ tx('config.helpPresentation.display.popover', '\u00CDcone de ajuda') }}</mat-option>\n <mat-option value=\"auto\">{{ tx('config.helpPresentation.display.auto', 'Autom\u00E1tica') }}</mat-option>\n <mat-option value=\"hidden\">{{ tx('config.helpPresentation.display.hidden', 'Oculta') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.inlineMaxLength.label', 'Limite inline') }}</mat-label>\n <input matInput type=\"number\" min=\"0\" [ngModel]=\"helpPresentationDraft.inlineMaxLength\"\n (ngModelChange)=\"onHelpPresentationInlineMaxLengthChange($event)\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.preferPopoverForControls.label', 'Preferir \u00EDcone em') }}</mat-label>\n <input matInput [ngModel]=\"getHelpPreferPopoverControlsText()\"\n (ngModelChange)=\"onHelpPreferPopoverControlsChange($event)\"\n [placeholder]=\"tx('config.helpPresentation.preferPopoverForControls.placeholder', 'toggle, checkbox, select')\" />\n </mat-form-field>\n </div>\n </section>\n\n <div class=\"actions-row\">\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"restoreHintsDefaults()\">\n <mat-icon>restore</mat-icon>\n {{ tx('config.hints.actions.restoreDefaults', 'Restaurar padr\u00F5es') }}\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('actions')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-acoes\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.actions.title', 'A\u00E7\u00F5es do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.actions.subtitle', 'Configure bot\u00F5es padr\u00E3o e a\u00E7\u00F5es customizadas.') }}</p>\n </div>\n </div>\n <praxis-actions-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-actions-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('rules')\">\n <div class=\"tab-content visual-builder-content\" data-testid=\"config-tab-panel-regras\">\n <div class=\"builder-header\">\n <div>\n <h3>{{ tx('config.rules.title', 'Regras visuais') }}</h3>\n <p class=\"text-caption\">{{ tx('config.rules.subtitle', 'Defina visibilidade, estilos e rea\u00E7\u00F5es baseadas em condi\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n @if (ruleDiagnostics.length) {\n <div class=\"rules-diagnostics\" data-testid=\"rules-diagnostics-panel\">\n <div class=\"rules-diagnostics__summary\">\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--total\">\n {{ tx('config.rules.summary.total', '{{count}} regras', { count: ruleDiagnosticsSummary.total }) }}\n </span>\n @if (ruleDiagnosticsSummary.invalid) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--error\">\n {{ tx('config.rules.summary.invalid', '{{count}} inv\u00E1lidas', { count: ruleDiagnosticsSummary.invalid }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.unsupported) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.unsupported', '{{count}} com propriedades rejeitadas', { count: ruleDiagnosticsSummary.unsupported }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.runtimeOnly) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.runtimeOnly', '{{count}} runtime only', { count: ruleDiagnosticsSummary.runtimeOnly }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.pendingReview) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.pendingReview', '{{count}} pendentes de revis\u00E3o', { count: ruleDiagnosticsSummary.pendingReview }) }}\n </span>\n }\n </div>\n <div class=\"rules-diagnostics__list\" [attr.aria-label]=\"tx('config.rules.diagnostics.ariaLabel', 'Diagn\u00F3stico das regras')\">\n @for (diagnostic of ruleDiagnostics; track diagnostic) {\n <article class=\"rules-diagnostics__item\"\n [class.rules-diagnostics__item--error]=\"getRuleStatusTone(diagnostic) === 'error'\"\n [class.rules-diagnostics__item--warn]=\"getRuleStatusTone(diagnostic) === 'warn'\">\n <div>\n <strong>{{ diagnostic.ruleName || diagnostic.ruleId }}</strong>\n <span>\n {{ tx('config.rules.diagnostics.targetConditionSummary', '{{targets}} alvo(s) \u00B7 {{conditions}} campo(s) na condi\u00E7\u00E3o', { targets: diagnostic.targetRefs.length, conditions: diagnostic.conditionRefs.length }) }}\n </span>\n @if (getRuleDiagnosticDetails(diagnostic).length) {\n <ul class=\"rules-diagnostics__details\">\n @for (detail of getRuleDiagnosticDetails(diagnostic); track detail) {\n <li>{{ detail }}</li>\n }\n </ul>\n }\n </div>\n <div class=\"rules-diagnostics__actions\">\n <span class=\"rules-diagnostics__status\">{{ getRuleStatusLabel(diagnostic) }}</span>\n @if (canApplyRulePropertyFix(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.fix.tooltip', 'Aplicar whitelist e saneamento de propriedades nesta regra')\"\n (click)=\"applyRulePropertyFix(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">auto_fix_high</mat-icon>\n {{ tx('config.rules.actions.fix', 'Corrigir') }}\n </button>\n }\n @if (diagnostic.status.includes('llm-generated-pending-review')) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [disabled]=\"!canAcceptPendingLlmRule(diagnostic)\"\n [matTooltip]=\"canAcceptPendingLlmRule(diagnostic) ? tx('config.rules.actions.accept.tooltip.ready', 'Aceitar sugest\u00E3o e atualizar estado visual') : tx('config.rules.actions.accept.tooltip.blocked', 'Corrija alvo, condi\u00E7\u00E3o e propriedades antes de aceitar')\"\n (click)=\"acceptPendingLlmRule(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.rules.actions.accept', 'Aceitar') }}\n </button>\n }\n @if (canOpenRuleJsonReview(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.reviewJson.tooltip', 'Abrir a aba JSON para revisar esta regra sem convers\u00E3o visual')\"\n (click)=\"openRuleJsonReview(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">data_object</mat-icon>\n {{ tx('config.rules.actions.reviewJson', 'Ver JSON') }}\n </button>\n }\n </div>\n </article>\n }\n </div>\n </div>\n } @else {\n <div class=\"rules-diagnostics rules-diagnostics--empty\" data-testid=\"rules-diagnostics-empty\">\n {{ tx('config.rules.empty', 'Nenhuma regra definida ainda. Crie uma regra para ver alvos, condi\u00E7\u00E3o, propriedades e compatibilidade do builder.') }}\n </div>\n }\n <praxis-visual-builder [config]=\"ruleBuilderConfig\" [initialRules]=\"ruleBuilderState\"\n (rulesChanged)=\"onRulesChanged($event)\"></praxis-visual-builder>\n <praxis-rule-properties-panel\n [rules]=\"currentRules\"\n [visualBlockNodes]=\"visualBlockNodeOptions\"\n (rulesChange)=\"onRulePropertiesChanged($event)\"\n ></praxis-rule-properties-panel>\n <mat-card class=\"command-rules-card\" data-testid=\"form-command-rules-editor\">\n <mat-card-title>{{ tx('config.commandRules.title', 'Comandos condicionais') }}</mat-card-title>\n <mat-card-subtitle>{{ tx('config.commandRules.subtitle', 'Execute a\u00E7\u00F5es globais quando uma condi\u00E7\u00E3o do formul\u00E1rio for satisfeita.') }}</mat-card-subtitle>\n <mat-card-content>\n <div class=\"command-rules-grid\">\n <div class=\"command-rules-toolbar\">\n <mat-form-field appearance=\"fill\" class=\"command-rules-select\">\n <mat-label>{{ tx('config.commandRules.command.label', 'Comando') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedCommandRuleId\" (selectionChange)=\"onCommandRuleSelectionChange()\">\n @for (rule of commandRules; track rule) {\n <mat-option [value]=\"rule.id\">\n {{ rule.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <button mat-stroked-button type=\"button\" (click)=\"addCommandRule()\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n {{ tx('config.commandRules.actions.add', 'Adicionar') }}\n </button>\n <button mat-stroked-button color=\"warn\" type=\"button\" (click)=\"deleteCommandRule()\" [disabled]=\"!selectedCommandRuleId\">\n <mat-icon aria-hidden=\"true\">delete</mat-icon>\n {{ tx('config.commandRules.actions.remove', 'Remover') }}\n </button>\n </div>\n\n @if (selectedCommandRuleId) {\n <div class=\"command-rule-condition-builder command-rules-full\">\n <praxis-visual-builder\n mode=\"condition\"\n [config]=\"ruleBuilderConfig\"\n [initialCondition]=\"commandRuleCondition\"\n (conditionChanged)=\"onCommandConditionChanged($event)\"\n ></praxis-visual-builder>\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.conditionJson.label', 'Condi\u00E7\u00E3o JSON Logic') }}</mat-label>\n <textarea\n matInput\n rows=\"5\"\n [(ngModel)]=\"commandRuleConditionJson\"\n [attr.aria-label]=\"tx('config.commandRules.conditionJson.ariaLabel', 'Condi\u00E7\u00E3o JSON Logic do comando condicional')\"\n ></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.globalAction.label', 'A\u00E7\u00E3o global') }}</mat-label>\n <mat-select [(ngModel)]=\"commandRuleActionId\" (selectionChange)=\"onCommandActionChange()\">\n @for (action of globalActionCatalog; track action) {\n <mat-option [value]=\"action.id\">\n {{ action.label || action.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.distinctBy.label', 'distinctBy') }}</mat-label>\n <input matInput [(ngModel)]=\"commandRuleDistinctBy\" [placeholder]=\"tx('config.commandRules.distinctBy.placeholder', 'ex.: idade')\" />\n </mat-form-field>\n\n @if (commandRuleActionSchema; as actionSchema) {\n <div\n class=\"command-rules-payload-fields command-rules-full\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.structuredPayload.title', 'Payload estruturado') }}</div>\n @if (actionSchema.editorMode !== 'surface-open') {\n @for (field of actionSchema.fields; track field) {\n @if (shouldShowCommandActionField(field)) {\n @if (field.type === 'toggle') {\n <mat-slide-toggle\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n >\n {{ field.label }}\n </mat-slide-toggle>\n } @else {\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ field.label }}</mat-label>\n @if (field.type === 'textarea' || field.type === 'json') {\n <textarea\n matInput\n [rows]=\"field.rows || (field.type === 'json' ? 3 : 2)\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || (field.type === 'json' ? '{ }' : '')\"\n [required]=\"isCommandActionFieldRequired(field)\"\n ></textarea>\n } @else {\n @if (field.type === 'select') {\n <mat-select\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [required]=\"isCommandActionFieldRequired(field)\"\n >\n @for (option of field.options || []; track option) {\n <mat-option [value]=\"option.value\">\n {{ option.label }}\n </mat-option>\n }\n </mat-select>\n } @else {\n <input\n matInput\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || ''\"\n [required]=\"isCommandActionFieldRequired(field)\"\n />\n }\n }\n @if (field.hint) {\n <mat-hint>{{ field.hint }}</mat-hint>\n }\n @if (hasCommandActionFieldError(field.key)) {\n <mat-error>\n {{ getCommandActionFieldError(field.key) }}\n </mat-error>\n }\n @if (!hasCommandActionFieldError(field.key) && isCommandActionFieldMissing(field)) {\n <mat-error>\n {{ tx('config.commandRules.validation.requiredField', 'Campo obrigat\u00F3rio.') }}\n </mat-error>\n }\n </mat-form-field>\n }\n }\n }\n } @else {\n <praxis-surface-open-action-editor\n class=\"command-rules-surface-editor\"\n data-testid=\"form-command-rule-surface-open-editor\"\n [value]=\"commandRuleSurfaceOpenPayload\"\n hostKind=\"dynamic-form\"\n (valueChange)=\"onCommandSurfaceOpenPayloadChange($event)\"\n ></praxis-surface-open-action-editor>\n }\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.advancedPayload.label', 'Payload JSON avan\u00E7ado') }}</mat-label>\n <textarea\n matInput\n rows=\"4\"\n [(ngModel)]=\"commandRulePayloadJson\"\n [attr.aria-label]=\"tx('config.commandRules.advancedPayload.ariaLabel', 'Payload JSON da a\u00E7\u00E3o global')\"\n ></textarea>\n </mat-form-field>\n\n <div class=\"command-rules-options\">\n <mat-slide-toggle [(ngModel)]=\"commandRuleDistinct\">{{ tx('config.commandRules.options.distinct', 'Evitar repeti\u00E7\u00E3o enquanto a condi\u00E7\u00E3o permanecer verdadeira') }}</mat-slide-toggle>\n <mat-slide-toggle [(ngModel)]=\"commandRuleRunOnInitialEvaluation\">{{ tx('config.commandRules.options.runOnInitialEvaluation', 'Executar tamb\u00E9m na avalia\u00E7\u00E3o inicial') }}</mat-slide-toggle>\n </div>\n\n @if (commandRuleAuthoringError) {\n <div class=\"preview-error command-rules-full\">\n <mat-icon aria-hidden=\"true\">warning</mat-icon>\n <span>{{ commandRuleAuthoringError }}</span>\n </div>\n }\n\n <div\n class=\"command-rule-preview command-rules-full\"\n [class.command-rule-preview--invalid]=\"commandRulePreview.state === 'invalid'\"\n data-testid=\"command-rule-preview\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.preview.title', 'Preview do comando') }}</div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.mode', 'Modo') }}</span>\n <strong>{{ commandRulePreview.executionMode }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.action', 'A\u00E7\u00E3o') }}</span>\n <strong>{{ commandRulePreview.actionId || '\u2014' }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.policy', 'Policy') }}</span>\n <code>{{ commandRulePreview.policy | json }}</code>\n </div>\n @if (commandRulePreview.diagnostics.length) {\n <div class=\"command-rule-preview__diagnostics\">\n <mat-icon aria-hidden=\"true\">{{ commandRulePreview.state === 'invalid' ? 'warning' : 'visibility' }}</mat-icon>\n <span>{{ commandRulePreview.diagnostics[0] }}</span>\n </div>\n }\n </div>\n\n <div class=\"command-rules-actions\">\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"applyCommandRule()\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.commandRules.actions.apply', 'Aplicar comando') }}\n </button>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('cascades')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-cascatas\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.cascades.title', 'Depend\u00EAncias entre campos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.cascades.subtitle', 'Configure cascatas e carregamento entre campos.') }}</p>\n </div>\n </div>\n <praxis-cascade-manager-tab [fields]=\"editedConfig.fieldMetadata || []\"\n (apply)=\"onCascadeApply($event)\"></praxis-cascade-manager-tab>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('messages')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-mensagens\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.messages.title', 'Mensagens e feedback') }}</h3>\n <p class=\"text-caption\">{{ tx('config.messages.subtitle', 'Padronize textos de sucesso, erro e confirma\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n <praxis-messages-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-messages-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('navigation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-navegacao\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.navigation.title', 'Navega\u00E7\u00E3o de retorno') }}</h3>\n <p class=\"text-caption\">{{ tx('config.navigation.subtitle', 'Defina o comportamento do bot\u00E3o Voltar em fluxos CRUD.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.navigation.returnTo.label', 'Rota de retorno') }}</mat-label>\n <input matInput id=\"returnTo\" [(ngModel)]=\"backConfig!.returnTo\" (ngModelChange)=\"onBackConfigChange()\" [placeholder]=\"tx('config.navigation.returnTo.placeholder', '/funcionarios')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"backConfig!.confirmOnDirty\" (ngModelChange)=\"onBackConfigChange()\">\n {{ tx('config.navigation.confirmOnDirty.label', 'Confirmar ao sair com altera\u00E7\u00F5es') }}\n </mat-slide-toggle>\n </div>\n <div class=\"block-status\" [class.block-status--implicit]=\"!isBackConfigBlockPersisted()\">\n <strong>{{ tx('config.navigation.backConfig.label', 'Back Config') }}</strong>\n @if (isBackConfigBlockPersisted()) {\n <span>{{ tx('config.navigation.backConfig.persisted', '`contextSnapshot.backConfig` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.navigation.backConfig.implicit', 'Bloco ausente no documento can\u00F4nico. Os valores exibidos s\u00E3o fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.navigation.note.label', 'Observa\u00E7\u00E3o:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.navigation.note.tooltip', 'Afeta o fluxo de navega\u00E7\u00E3o do CRUD e pode ser sobreposto por metadados do recurso.')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('json')\">\n <div class=\"tab-content json-tab-content\" data-testid=\"config-tab-panel-json\">\n <mat-card class=\"section-card section-card--json\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.json.title', 'Configura\u00E7\u00E3o JSON') }}</h3>\n <p class=\"text-caption\">{{ tx('config.json.subtitle', 'Edi\u00E7\u00E3o avan\u00E7ada do documento can\u00F4nico de autoria do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <form-json-config-editor [document]=\"jsonDocument\" (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\" (editorEvent)=\"onJsonEditorEvent($event)\">\n </form-json-config-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n</mat-tab-group>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-width:0}.mobile-tab-selector{display:none;flex:0 0 auto;padding:8px 16px 0;background:var(--md-sys-color-surface)}.mobile-tab-selector__field{width:100%}.config-tabs{flex:1 1 auto;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs{display:flex;flex-direction:column}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-wrapper{flex:1;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-content{height:100%;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;padding:0!important}.tab-content{padding:16px 20px 20px;flex:1;min-width:0;box-sizing:border-box}.json-tab-content{min-width:0;padding:12px 16px 16px}.section-card--json{display:flex;flex:1;min-height:calc(100vh - 180px);border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.section-card--json>mat-card-content{display:flex;flex:1;min-width:0;min-height:0;flex-direction:column}.section-card--json form-json-config-editor{display:block;flex:1;min-width:0;min-height:0}.form-row{display:block;margin-bottom:12px}.form-grid{display:grid;gap:12px}.section-help{display:inline-flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:12px}.section-help__label{font-weight:500}.grid-2-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}.grid-2-cols--compact{gap:12px}.w-100{width:100%}.visual-builder-content{padding:0!important;height:100%;min-width:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:16px}.visual-builder-content>praxis-visual-builder{flex:0 0 auto;min-width:0;min-height:clamp(360px,48vh,560px)}.visual-builder-content>praxis-rule-properties-panel{flex:0 0 auto;display:block;min-width:0;padding:0 16px 24px;box-sizing:border-box}.rules-diagnostics{flex:0 0 auto;display:grid;gap:10px;padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.rules-diagnostics--empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.rules-diagnostics__summary,.rules-diagnostics__list{display:flex;flex-wrap:wrap;gap:8px}.rules-diagnostics__pill{display:inline-flex;align-items:center;min-height:24px;padding:3px 9px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:12px;font-weight:600}.rules-diagnostics__pill--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container) 72%,transparent);color:var(--md-sys-color-on-tertiary-container)}.rules-diagnostics__pill--error{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.rules-diagnostics__item{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;min-width:min(100%,280px);padding:8px 10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container)}.rules-diagnostics__item>div{display:grid;gap:2px;min-width:0}.rules-diagnostics__item strong{color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rules-diagnostics__item span{color:var(--md-sys-color-on-surface-variant);font-size:11px}.rules-diagnostics__actions{flex:0 0 auto;display:flex;align-items:center;gap:8px}.rules-diagnostics__details{display:grid;gap:2px;margin:4px 0 0;padding-left:16px;color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35}.rules-diagnostics__details li{overflow-wrap:anywhere}.rules-diagnostics__item--warn{border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 52%,var(--md-sys-color-outline-variant))}.rules-diagnostics__item--error{border-color:var(--md-sys-color-error)}.rules-diagnostics__status{font-weight:600;margin-top:1px}.rules-diagnostics__action{min-width:0;height:28px;padding:0 10px;border-radius:999px;font-size:12px;line-height:1}.rules-diagnostics__action mat-icon{width:16px;height:16px;margin:0 4px 0 0;font-size:16px}.json-field{width:100%}.presentation-layout{display:flex;gap:20px;align-items:flex-start}.presentation-controls{flex:1 1 60%;display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:14px 18px}.control{display:flex;flex-direction:column}.control-span{grid-column:1/-1}.block-status{grid-column:1/-1;display:flex;gap:8px;align-items:flex-start;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 35%,transparent);color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.45}.block-status strong{min-width:112px;font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant)}.block-status--implicit{background:color-mix(in srgb,var(--md-sys-color-surface-variant) 42%,transparent);border:1px dashed var(--md-sys-color-outline)}.block-status--readonly{margin-bottom:12px}.block-status code{font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:11px}.control__label{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:6px}.toggle-group{width:100%}.control--inline{grid-column:1/-1;display:flex;gap:16px;align-items:center}.presentation-preview{flex:0 0 360px;position:sticky;top:16px}.preview-card{border:1px solid var(--md-sys-color-outline);border-radius:12px;padding:14px;background:var(--md-sys-color-surface-container)}.preview-row{display:flex;gap:8px;padding:6px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.preview-row:last-child{border-bottom:none}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.presentation-preview .praxis-presentation__label{color:var(--md-sys-color-on-surface-variant)}.presentation-preview .praxis-presentation__value{color:var(--md-sys-color-on-surface)}.presentation-preview .presentation-mode.pres-density-cozy .preview-row{padding:6px 0}.presentation-preview .presentation-mode.pres-density-compact .preview-row,.presentation-preview .presentation-mode.pres-compact .preview-row{padding:2px 0}.presentation-preview .presentation-mode.pres-label-left .preview-row{display:grid;grid-template-columns:var(--pfx-pres-label-width, 140px) 1fr;align-items:baseline;column-gap:10px}.presentation-preview .presentation-mode.pres-label-left .praxis-presentation__label{margin:0;text-align:var(--pfx-pres-label-align, start)}.presentation-preview .presentation-mode .praxis-presentation__value{text-align:var(--pfx-pres-value-align, start)}.presentation-preview h4{margin:0 0 8px;color:var(--md-sys-color-on-surface);font-size:1rem}.section-card{border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-level1, none)}.section-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.tab-content--dense{padding:12px 16px 16px}.tab-content--dense .section-header,.tab-content--dense .form-row{margin-bottom:8px}.section-header h3{margin:0;font-size:1.05rem;color:var(--md-sys-color-on-surface)}.text-caption{margin:6px 0 0;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.section-header--compact{margin-bottom:8px}.section-body{display:block}.section-body--flex{flex:1;min-height:0;display:flex;flex-direction:column}.builder-header{padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.builder-header h3{margin:0;font-size:1rem;color:var(--md-sys-color-on-surface)}.hint{margin:8px 0 0;padding:10px 12px;border-radius:10px;border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface-variant)}.meta-card{display:grid;gap:6px;padding:10px 12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.meta-row{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.meta-row strong{color:var(--md-sys-color-on-surface);font-weight:600}.runtime-contract-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.runtime-contract-field{display:grid;gap:6px;padding:12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.runtime-contract-label{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.runtime-contract-code{display:block;font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:12px;line-height:1.45;color:var(--md-sys-color-on-surface);word-break:break-word;white-space:normal}.command-rules-card{margin:16px;min-width:0;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container)}.command-rules-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:12px;align-items:start;min-width:0}.command-rules-toolbar,.command-rules-options,.command-rules-actions{grid-column:1/-1;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.command-rules-select{min-width:min(320px,100%)}.command-rules-full{grid-column:1/-1}.command-rule-condition-builder{min-height:420px;overflow:hidden;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-payload-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px;min-width:0;padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-section-title{grid-column:1/-1;font-size:12px;font-weight:600;color:var(--md-sys-color-on-surface-variant);text-transform:uppercase}.command-rules-surface-editor{grid-column:1/-1}.command-rule-preview{display:grid;gap:8px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.command-rule-preview--invalid{border-color:var(--md-sys-color-error)}.command-rule-preview__row{display:grid;grid-template-columns:minmax(96px,.35fr) minmax(0,1fr);gap:8px;align-items:start;min-width:0}.command-rule-preview__row span{color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:600}.command-rule-preview__row strong,.command-rule-preview__row code{min-width:0;overflow-wrap:anywhere}.command-rule-preview__diagnostics{display:flex;gap:8px;align-items:flex-start;color:var(--md-sys-color-on-surface-variant)}@media(max-width:768px){.mobile-tab-selector{display:block}::ng-deep .mat-mdc-tab-group.config-tabs>.mat-mdc-tab-header{display:none}.tab-content{padding:12px}.json-tab-content{padding:8px}.section-card--json{min-height:auto}}\n"] }]
31631
+ ], providers: [FormConfigService, providePraxisI18nConfig(PRAXIS_DYNAMIC_FORM_I18N_CONFIG)], template: "<div class=\"mobile-tab-selector\">\n <mat-form-field appearance=\"outline\" class=\"mobile-tab-selector__field\">\n <mat-label>{{ tx('config.tabs.mobileLabel', 'Se\u00E7\u00E3o do editor') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedConfigTabIndex\" data-testid=\"dynamic-form-config-editor-mobile-tabs\">\n @for (tab of configTabOptions; track tab.key) {\n <mat-option [value]=\"tab.index\">{{ tab.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n\n<mat-tab-group class=\"config-tabs\" data-testid=\"dynamic-form-config-editor-tabs\" [(selectedIndex)]=\"selectedConfigTabIndex\">\n <mat-tab [label]=\"configTabLabel('general')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-geral\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.title', 'Dados do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.general.subtitle', 'Defina o modo de dados e o contexto de edi\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <div class=\"form-modes\">\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.general.inputMode.label') }}</label>\n <mat-button-toggle-group [ngModel]=\"inputMode\" (ngModelChange)=\"inputMode = $event; onInputModeChange()\" [attr.aria-label]=\"tx('config.general.inputMode.label')\">\n <mat-button-toggle value=\"create\">{{ tx('config.general.inputMode.create') }}</mat-button-toggle>\n <mat-button-toggle value=\"edit\">{{ tx('config.general.inputMode.edit') }}</mat-button-toggle>\n <mat-button-toggle value=\"view\">{{ tx('config.general.inputMode.view') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n @if (supportsPresentationSettings) {\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.general.displayMode.label') }}</label>\n <mat-button-toggle-group [ngModel]=\"displayMode\" (ngModelChange)=\"onDisplayModeChange($event)\" [attr.aria-label]=\"tx('config.general.displayMode.label')\">\n <mat-button-toggle value=\"automatic\">{{ tx('config.general.displayMode.automatic') }}</mat-button-toggle>\n <mat-button-toggle value=\"fields\">{{ tx('config.general.displayMode.fields') }}</mat-button-toggle>\n <mat-button-toggle value=\"presentation\">{{ tx('config.general.displayMode.presentation') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <p class=\"display-result\" role=\"status\">{{ tx(displayModeHint) }}</p>\n @if (inputMode !== 'view' && inputPresentationMode === true) {\n <button mat-stroked-button type=\"button\" (click)=\"useViewMode()\">{{ tx('config.general.displayMode.useView') }}</button>\n }\n <button mat-button type=\"button\" (click)=\"openPresentationStyle()\">{{ tx('config.general.displayMode.openStyle') }}</button>\n }\n </div>\n </mat-card-content>\n </mat-card>\n\n @if (hasResolvedRuntimeContract()) {\n <mat-card\n class=\"section-card\"\n data-testid=\"config-tab-runtime-contract\"\n >\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.general.runtimeContract.title', 'Contrato Runtime Resolvido') }}</h3>\n <p class=\"text-caption\">\n {{ tx('config.general.runtimeContract.subtitle', 'Visualiza\u00E7\u00E3o somente leitura do contrato backend resolvido pelo host atual.') }}\n </p>\n </div>\n </div>\n <div class=\"block-status block-status--readonly\">\n <strong>{{ tx('config.general.runtimeContract.runtimeLabel', 'Runtime') }}</strong>\n <span>\n {{ tx('config.general.runtimeContract.readonly', 'Esses valores v\u00EAm do host/runtime atual e n\u00E3o s\u00E3o persistidos em `bindings` nem em `contextSnapshot`.') }}\n </span>\n </div>\n <div class=\"runtime-contract-grid\">\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaUrl', 'Schema URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.schemaUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.schemaSource', 'Origem do schema') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.schemaSource) }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitMethod', 'Submit method') }}</span>\n <strong>{{ runtimeContract?.submitMethod || '\u2014' }}</strong>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitUrl', 'Submit URL') }}</span>\n <code class=\"runtime-contract-code\">{{ runtimeContract?.submitUrl || '\u2014' }}</code>\n </div>\n <div class=\"runtime-contract-field\">\n <span class=\"runtime-contract-label\">{{ tx('config.general.runtimeContract.submitSource', 'Origem do submit') }}</span>\n <strong>{{ describeRuntimeSource(runtimeContract?.submitSource) }}</strong>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n }\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('schema')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-schema\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.schema.title', 'Valida\u00E7\u00E3o de schema') }}</h3>\n <p class=\"text-caption\">{{ tx('config.schema.subtitle', 'Controle avisos quando o schema do servidor mudar.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.notify.label', 'Notificar quando desatualizado') }}</mat-label>\n <mat-select [(ngModel)]=\"schemaPrefs.notifyIfOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-notify')\">\n <mat-option value=\"both\">{{ tx('config.schema.notify.both', 'Banner + Snackbar') }}</mat-option>\n <mat-option value=\"inline\">{{ tx('config.schema.notify.inline', 'Somente Banner') }}</mat-option>\n <mat-option value=\"snackbar\">{{ tx('config.schema.notify.snackbar', 'Somente Snackbar') }}</mat-option>\n <mat-option value=\"none\">{{ tx('config.schema.notify.none', 'Nenhum') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.schema.snooze.label', 'Intervalo de sil\u00EAncio (ms)') }}</mat-label>\n <input matInput type=\"number\" [(ngModel)]=\"schemaPrefs.snoozeMs\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-snooze')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"schemaPrefs.autoOpenSettingsOnOutdated\" (ngModelChange)=\"onSchemaPrefsChange('schema-prefs-auto-open')\">\n {{ tx('config.schema.autoOpenSettings', 'Abrir configura\u00E7\u00F5es automaticamente') }}\n </mat-slide-toggle>\n </div>\n @if (serverMeta) {\n <div class=\"form-row\">\n <div class=\"meta-card\">\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.serverHash', 'Server hash') }}</span>\n <strong>{{ serverMeta.serverHash || '\u2014' }}</strong>\n </div>\n <div class=\"meta-row\">\n <span>{{ tx('config.schema.meta.lastVerifiedAt', '\u00DAltima verifica\u00E7\u00E3o') }}</span>\n <strong>{{ serverMeta.lastVerifiedAt || '\u2014' }}</strong>\n </div>\n </div>\n </div>\n }\n <div class=\"block-status\" [class.block-status--implicit]=\"!isSchemaPrefsBlockPersisted()\">\n <strong>{{ tx('config.schema.prefs.label', 'Schema Prefs') }}</strong>\n @if (isSchemaPrefsBlockPersisted()) {\n <span>{{ tx('config.schema.prefs.persisted', '`contextSnapshot.schemaPrefs` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.schema.prefs.implicit', 'Bloco ausente no documento can\u00F4nico. Os controles exibem fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('layout')\">\n <div class=\"tab-content tab-content--full\" data-testid=\"config-tab-panel-layout\">\n <div class=\"section-header section-header--compact\">\n <div>\n <h3>{{ tx('config.layout.title', 'Layout do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.layout.subtitle', 'Organize se\u00E7\u00F5es, linhas e campos com drag & drop.') }}</p>\n </div>\n </div>\n <div class=\"section-body section-body--flex\">\n <praxis-layout-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"\n (select)=\"onLayoutSelect($event)\"></praxis-layout-editor>\n </div>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hooks')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-hooks\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hooks.title', 'Hooks de ciclo de vida') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hooks.subtitle', 'Automatize a\u00E7\u00F5es nos eventos do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-hooks-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-hooks-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n @if (isPresentationMode) {\n <mat-tab [label]=\"configTabLabel('presentation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-presentation\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.presentation.title', 'Modo Apresenta\u00E7\u00E3o') }}</h3>\n <p class=\"text-caption\">{{ tx('config.presentation.subtitle', 'Configura\u00E7\u00F5es de exibi\u00E7\u00E3o aplicadas somente ao modo apresenta\u00E7\u00E3o.') }}</p>\n </div>\n </div>\n <p class=\"display-result\" role=\"status\">{{ tx(displayModeHint) }}</p>\n <div class=\"presentation-layout\">\n <div class=\"presentation-controls\">\n <div class=\"block-status control-span\" [class.block-status--implicit]=\"!isPresentationBlockPersisted()\">\n <strong>{{ tx('config.presentation.block.label', 'Presentation') }}</strong>\n @if (isPresentationBlockPersisted()) {\n <span>{{ tx('config.presentation.block.persisted', '`contextSnapshot.presentation` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.presentation.block.implicit', 'Bloco ausente no documento can\u00F4nico. A pr\u00E9-visualiza\u00E7\u00E3o usa fallback local e n\u00E3o ser\u00E1 salva at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelPosition.label', 'Posi\u00E7\u00E3o do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelPosition\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-position')\" [attr.aria-label]=\"tx('config.presentation.labelPosition.ariaLabel', 'Posi\u00E7\u00E3o do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"above\">\n <mat-icon>view_stream</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.above', 'Acima') }}</span>\n </mat-button-toggle>\n <mat-button-toggle value=\"left\">\n <mat-icon>view_column</mat-icon>\n <span class=\"sr-only\">{{ tx('config.presentation.labelPosition.left', '\u00C0 esquerda') }}</span>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control control-span\">\n <label class=\"control__label\">{{ tx('config.presentation.density.label', 'Densidade') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.density\" (ngModelChange)=\"onPresentationPrefsChange('presentation-density')\" [attr.aria-label]=\"tx('config.presentation.density.ariaLabel', 'Densidade')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"comfortable\">{{ tx('config.presentation.density.comfortable', 'Confort\u00E1vel') }}</mat-button-toggle>\n <mat-button-toggle value=\"cozy\">{{ tx('config.presentation.density.cozy', 'Intermedi\u00E1ria') }}</mat-button-toggle>\n <mat-button-toggle value=\"compact\">{{ tx('config.presentation.density.compact', 'Compacta') }}</mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.labelAlign.label', 'Alinhamento do r\u00F3tulo') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.labelAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-align')\" [attr.aria-label]=\"tx('config.presentation.labelAlign.ariaLabel', 'Alinhamento do r\u00F3tulo')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\" [aria-label]=\"tx('config.presentation.align.start')\" [matTooltip]=\"tx('config.presentation.align.start')\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\" [aria-label]=\"tx('config.presentation.align.center')\" [matTooltip]=\"tx('config.presentation.align.center')\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\" [aria-label]=\"tx('config.presentation.align.end')\" [matTooltip]=\"tx('config.presentation.align.end')\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <label class=\"control__label\">{{ tx('config.presentation.valueAlign.label', 'Alinhamento do valor') }}</label>\n <mat-button-toggle-group [(ngModel)]=\"presentationPrefs.valueAlign\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-align')\" [attr.aria-label]=\"tx('config.presentation.valueAlign.ariaLabel', 'Alinhamento do valor')\"\n class=\"toggle-group\">\n <mat-button-toggle value=\"start\" [aria-label]=\"tx('config.presentation.align.start')\" [matTooltip]=\"tx('config.presentation.align.start')\"><mat-icon>format_align_left</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"center\" [aria-label]=\"tx('config.presentation.align.center')\" [matTooltip]=\"tx('config.presentation.align.center')\"><mat-icon>format_align_center</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"end\" [aria-label]=\"tx('config.presentation.align.end')\" [matTooltip]=\"tx('config.presentation.align.end')\"><mat-icon>format_align_right</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelFontSize.label', 'Tamanho do r\u00F3tulo') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" step=\"any\" [(ngModel)]=\"presentationPrefs.labelFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-font-size')\"\n [placeholder]=\"tx('config.presentation.labelFontSize.placeholder', 'ex.: 12')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.valueFontSize.label', 'Tamanho do valor') }}</mat-label>\n <input matInput type=\"number\" min=\"10\" step=\"any\" [(ngModel)]=\"presentationPrefs.valueFontSize\" (ngModelChange)=\"onPresentationPrefsChange('presentation-value-font-size')\"\n [placeholder]=\"tx('config.presentation.valueFontSize.placeholder', 'ex.: 16')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.presentation.labelWidth.label', 'Largura do r\u00F3tulo (label \u00E0 esquerda)') }}</mat-label>\n <input matInput type=\"number\" min=\"60\" [disabled]=\"presentationPrefs.labelPosition !== 'left'\" [(ngModel)]=\"presentationPrefs.labelWidth\" (ngModelChange)=\"onPresentationPrefsChange('presentation-label-width')\"\n [placeholder]=\"tx('config.presentation.labelWidth.placeholder', 'ex.: 140')\" />\n <span matSuffix>px</span>\n </mat-form-field>\n </div>\n <div class=\"control control--inline\">\n <mat-slide-toggle [(ngModel)]=\"presentationPrefs.compact\" (ngModelChange)=\"onPresentationPrefsChange('presentation-compact')\">\n {{ tx('config.presentation.options.compactMode', 'Modo compacto') }}\n </mat-slide-toggle>\n <mat-checkbox [(ngModel)]=\"truncatePreview\">\n {{ tx('config.presentation.options.truncateValues', 'Truncar valores') }}\n </mat-checkbox>\n </div>\n </div>\n <div class=\"presentation-preview\">\n <h4>{{ tx('config.presentation.preview.title', 'Pr\u00E9-visualiza\u00E7\u00E3o') }}</h4>\n <p class=\"text-caption\">{{ tx('config.presentation.preview.sampleHint') }}</p>\n <div class=\"preview-card\">\n <div class=\"praxis-dynamic-form presentation-mode\" [ngClass]=\"{\n 'pres-compact': !!presentationPrefs.compact,\n 'pres-label-left': presentationPrefs.labelPosition === 'left',\n 'pres-label-above': presentationPrefs.labelPosition === 'above',\n 'pres-density-compact': presentationPrefs.density === 'compact',\n 'pres-density-cozy': presentationPrefs.density === 'cozy'\n }\" [style.--pfx-pres-label-size]=\"(presentationPrefs.labelFontSize || 12) + 'px'\"\n [style.--pfx-pres-value-size]=\"(presentationPrefs.valueFontSize || 16) + 'px'\"\n [style.--pfx-pres-label-width]=\"(presentationPrefs.labelWidth || 140) + 'px'\"\n [style.--pfx-pres-label-align]=\"presentationPrefs.labelAlign || 'start'\"\n [style.--pfx-pres-value-align]=\"presentationPrefs.valueAlign || 'start'\">\n @for (item of previewItems; track item) {\n <div class=\"preview-row\">\n <span class=\"praxis-presentation__label\">{{ item.label }}</span>\n <span class=\"praxis-presentation__value\" [attr.title]=\"truncatePreview ? item.value : null\"\n [style.maxWidth]=\"truncatePreview ? '280px' : null\"\n [style.overflow]=\"truncatePreview ? 'hidden' : null\"\n [style.textOverflow]=\"truncatePreview ? 'ellipsis' : null\"\n [style.whiteSpace]=\"truncatePreview ? 'nowrap' : 'normal'\">\n {{ item.value }}\n </span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n }\n <mat-tab [label]=\"configTabLabel('behavior')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-comportamento\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.behavior.title', 'Comportamento') }}</h3>\n <p class=\"text-caption\">{{ tx('config.behavior.subtitle', 'Ajuste valida\u00E7\u00F5es e respostas do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <praxis-behavior-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-behavior-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('hints')\">\n <div class=\"tab-content tab-content--dense\" data-testid=\"config-tab-panel-hints\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.hints.title', 'Dicas dos modos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.hints.subtitle', 'Personalize textos de apoio para modos de dados e estados de UI.') }}</p>\n </div>\n </div>\n <p class=\"text-caption\">{{ tx('config.hints.description', 'Personalize os textos usados como tooltip/hint para modos de dados e modos globais de UI.') }}</p>\n\n <div class=\"grid-2-cols grid-2-cols--compact\">\n <section>\n <h4>{{ tx('config.hints.dataModes.title', 'Modos de dados') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.create.label', 'Criar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.create\"\n (ngModelChange)=\"updateDirtyState('hints-data-create')\" [placeholder]=\"tx('config.hints.dataModes.create.placeholder', 'Ex.: Preencha os campos obrigat\u00F3rios.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.edit.label', 'Editar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.edit\"\n (ngModelChange)=\"updateDirtyState('hints-data-edit')\" [placeholder]=\"tx('config.hints.dataModes.edit.placeholder', 'Ex.: Revise os dados antes de salvar.')\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.dataModes.view.label', 'Visualizar') }}</mat-label>\n <input matInput [(ngModel)]=\"editedConfig.hints!.dataModes.view\"\n (ngModelChange)=\"updateDirtyState('hints-data-view')\" [placeholder]=\"tx('config.hints.dataModes.view.placeholder', 'Ex.: Visualiza\u00E7\u00E3o somente leitura.')\" />\n </mat-form-field>\n </section>\n\n <section>\n <h4>{{ tx('config.hints.uiModes.title', 'Modos de UI') }}</h4>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.presentation.label', 'Apresenta\u00E7\u00E3o') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.presentation\"\n (ngModelChange)=\"updateDirtyState('hints-ui-presentation')\" [placeholder]=\"tx('config.hints.uiModes.presentation.placeholder', 'Ex.: Modo compacto para leitura r\u00E1pida.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.readonly.label', 'Leitura (readonly)') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.readonly\"\n (ngModelChange)=\"updateDirtyState('hints-ui-readonly')\" [placeholder]=\"tx('config.hints.uiModes.readonly.placeholder', 'Ex.: Campos bloqueados para edi\u00E7\u00E3o.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.disabled.label', 'Desabilitado') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.disabled\"\n (ngModelChange)=\"updateDirtyState('hints-ui-disabled')\" [placeholder]=\"tx('config.hints.uiModes.disabled.placeholder', 'Ex.: Fun\u00E7\u00E3o indispon\u00EDvel no momento.')\"></textarea>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.hints.uiModes.visible.label', 'Vis\u00EDvel') }}</mat-label>\n <textarea matInput rows=\"2\" [(ngModel)]=\"editedConfig.hints!.uiModes.visible\"\n (ngModelChange)=\"updateDirtyState('hints-ui-visible')\" [placeholder]=\"tx('config.hints.uiModes.visible.placeholder', 'Ex.: Campo exibido conforme permiss\u00F5es.')\"></textarea>\n </mat-form-field>\n </section>\n </div>\n\n <section>\n <h4>{{ tx('config.helpPresentation.title', 'Apresenta\u00E7\u00E3o das ajudas dos campos') }}</h4>\n <p class=\"text-caption\">{{ tx('config.helpPresentation.description', 'Controle como hint/helpText dos campos aparece em formul\u00E1rios densos. Erros de valida\u00E7\u00E3o continuam inline.') }}</p>\n <div class=\"grid-3-cols\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.display.label', 'Exibi\u00E7\u00E3o') }}</mat-label>\n <mat-select [ngModel]=\"helpPresentationDraft.display\" (ngModelChange)=\"onHelpPresentationDisplayChange($event)\">\n <mat-option value=\"inline\">{{ tx('config.helpPresentation.display.inline', 'Inline') }}</mat-option>\n <mat-option value=\"popover\">{{ tx('config.helpPresentation.display.popover', '\u00CDcone de ajuda') }}</mat-option>\n <mat-option value=\"auto\">{{ tx('config.helpPresentation.display.auto', 'Autom\u00E1tica') }}</mat-option>\n <mat-option value=\"hidden\">{{ tx('config.helpPresentation.display.hidden', 'Oculta') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.inlineMaxLength.label', 'Limite inline') }}</mat-label>\n <input matInput type=\"number\" min=\"0\" [ngModel]=\"helpPresentationDraft.inlineMaxLength\"\n (ngModelChange)=\"onHelpPresentationInlineMaxLengthChange($event)\" />\n </mat-form-field>\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.helpPresentation.preferPopoverForControls.label', 'Preferir \u00EDcone em') }}</mat-label>\n <input matInput [ngModel]=\"getHelpPreferPopoverControlsText()\"\n (ngModelChange)=\"onHelpPreferPopoverControlsChange($event)\"\n [placeholder]=\"tx('config.helpPresentation.preferPopoverForControls.placeholder', 'toggle, checkbox, select')\" />\n </mat-form-field>\n </div>\n </section>\n\n <div class=\"actions-row\">\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"restoreHintsDefaults()\">\n <mat-icon>restore</mat-icon>\n {{ tx('config.hints.actions.restoreDefaults', 'Restaurar padr\u00F5es') }}\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('actions')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-acoes\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.actions.title', 'A\u00E7\u00F5es do formul\u00E1rio') }}</h3>\n <p class=\"text-caption\">{{ tx('config.actions.subtitle', 'Configure bot\u00F5es padr\u00E3o e a\u00E7\u00F5es customizadas.') }}</p>\n </div>\n </div>\n <praxis-actions-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-actions-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('rules')\">\n <div class=\"tab-content visual-builder-content\" data-testid=\"config-tab-panel-regras\">\n <div class=\"builder-header\">\n <div>\n <h3>{{ tx('config.rules.title', 'Regras visuais') }}</h3>\n <p class=\"text-caption\">{{ tx('config.rules.subtitle', 'Defina visibilidade, estilos e rea\u00E7\u00F5es baseadas em condi\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n @if (ruleDiagnostics.length) {\n <div class=\"rules-diagnostics\" data-testid=\"rules-diagnostics-panel\">\n <div class=\"rules-diagnostics__summary\">\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--total\">\n {{ tx('config.rules.summary.total', '{{count}} regras', { count: ruleDiagnosticsSummary.total }) }}\n </span>\n @if (ruleDiagnosticsSummary.invalid) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--error\">\n {{ tx('config.rules.summary.invalid', '{{count}} inv\u00E1lidas', { count: ruleDiagnosticsSummary.invalid }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.unsupported) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.unsupported', '{{count}} com propriedades rejeitadas', { count: ruleDiagnosticsSummary.unsupported }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.runtimeOnly) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.runtimeOnly', '{{count}} runtime only', { count: ruleDiagnosticsSummary.runtimeOnly }) }}\n </span>\n }\n @if (ruleDiagnosticsSummary.pendingReview) {\n <span class=\"rules-diagnostics__pill rules-diagnostics__pill--warn\">\n {{ tx('config.rules.summary.pendingReview', '{{count}} pendentes de revis\u00E3o', { count: ruleDiagnosticsSummary.pendingReview }) }}\n </span>\n }\n </div>\n <div class=\"rules-diagnostics__list\" [attr.aria-label]=\"tx('config.rules.diagnostics.ariaLabel', 'Diagn\u00F3stico das regras')\">\n @for (diagnostic of ruleDiagnostics; track diagnostic) {\n <article class=\"rules-diagnostics__item\"\n [class.rules-diagnostics__item--error]=\"getRuleStatusTone(diagnostic) === 'error'\"\n [class.rules-diagnostics__item--warn]=\"getRuleStatusTone(diagnostic) === 'warn'\">\n <div>\n <strong>{{ diagnostic.ruleName || diagnostic.ruleId }}</strong>\n <span>\n {{ tx('config.rules.diagnostics.targetConditionSummary', '{{targets}} alvo(s) \u00B7 {{conditions}} campo(s) na condi\u00E7\u00E3o', { targets: diagnostic.targetRefs.length, conditions: diagnostic.conditionRefs.length }) }}\n </span>\n @if (getRuleDiagnosticDetails(diagnostic).length) {\n <ul class=\"rules-diagnostics__details\">\n @for (detail of getRuleDiagnosticDetails(diagnostic); track detail) {\n <li>{{ detail }}</li>\n }\n </ul>\n }\n </div>\n <div class=\"rules-diagnostics__actions\">\n <span class=\"rules-diagnostics__status\">{{ getRuleStatusLabel(diagnostic) }}</span>\n @if (canApplyRulePropertyFix(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.fix.tooltip', 'Aplicar whitelist e saneamento de propriedades nesta regra')\"\n (click)=\"applyRulePropertyFix(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">auto_fix_high</mat-icon>\n {{ tx('config.rules.actions.fix', 'Corrigir') }}\n </button>\n }\n @if (diagnostic.status.includes('llm-generated-pending-review')) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [disabled]=\"!canAcceptPendingLlmRule(diagnostic)\"\n [matTooltip]=\"canAcceptPendingLlmRule(diagnostic) ? tx('config.rules.actions.accept.tooltip.ready', 'Aceitar sugest\u00E3o e atualizar estado visual') : tx('config.rules.actions.accept.tooltip.blocked', 'Corrija alvo, condi\u00E7\u00E3o e propriedades antes de aceitar')\"\n (click)=\"acceptPendingLlmRule(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.rules.actions.accept', 'Aceitar') }}\n </button>\n }\n @if (canOpenRuleJsonReview(diagnostic)) {\n <button\n mat-stroked-button\n type=\"button\"\n class=\"rules-diagnostics__action\"\n [matTooltip]=\"tx('config.rules.actions.reviewJson.tooltip', 'Abrir a aba JSON para revisar esta regra sem convers\u00E3o visual')\"\n (click)=\"openRuleJsonReview(diagnostic.ruleId)\">\n <mat-icon aria-hidden=\"true\">data_object</mat-icon>\n {{ tx('config.rules.actions.reviewJson', 'Ver JSON') }}\n </button>\n }\n </div>\n </article>\n }\n </div>\n </div>\n } @else {\n <div class=\"rules-diagnostics rules-diagnostics--empty\" data-testid=\"rules-diagnostics-empty\">\n {{ tx('config.rules.empty', 'Nenhuma regra definida ainda. Crie uma regra para ver alvos, condi\u00E7\u00E3o, propriedades e compatibilidade do builder.') }}\n </div>\n }\n <praxis-visual-builder [config]=\"ruleBuilderConfig\" [initialRules]=\"ruleBuilderState\"\n (rulesChanged)=\"onRulesChanged($event)\"></praxis-visual-builder>\n <praxis-rule-properties-panel\n [rules]=\"currentRules\"\n [visualBlockNodes]=\"visualBlockNodeOptions\"\n (rulesChange)=\"onRulePropertiesChanged($event)\"\n ></praxis-rule-properties-panel>\n <mat-card class=\"command-rules-card\" data-testid=\"form-command-rules-editor\">\n <mat-card-title>{{ tx('config.commandRules.title', 'Comandos condicionais') }}</mat-card-title>\n <mat-card-subtitle>{{ tx('config.commandRules.subtitle', 'Execute a\u00E7\u00F5es globais quando uma condi\u00E7\u00E3o do formul\u00E1rio for satisfeita.') }}</mat-card-subtitle>\n <mat-card-content>\n <div class=\"command-rules-grid\">\n <div class=\"command-rules-toolbar\">\n <mat-form-field appearance=\"fill\" class=\"command-rules-select\">\n <mat-label>{{ tx('config.commandRules.command.label', 'Comando') }}</mat-label>\n <mat-select [(ngModel)]=\"selectedCommandRuleId\" (selectionChange)=\"onCommandRuleSelectionChange()\">\n @for (rule of commandRules; track rule) {\n <mat-option [value]=\"rule.id\">\n {{ rule.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n <button mat-stroked-button type=\"button\" (click)=\"addCommandRule()\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n {{ tx('config.commandRules.actions.add', 'Adicionar') }}\n </button>\n <button mat-stroked-button color=\"warn\" type=\"button\" (click)=\"deleteCommandRule()\" [disabled]=\"!selectedCommandRuleId\">\n <mat-icon aria-hidden=\"true\">delete</mat-icon>\n {{ tx('config.commandRules.actions.remove', 'Remover') }}\n </button>\n </div>\n\n @if (selectedCommandRuleId) {\n <div class=\"command-rule-condition-builder command-rules-full\">\n <praxis-visual-builder\n mode=\"condition\"\n [config]=\"ruleBuilderConfig\"\n [initialCondition]=\"commandRuleCondition\"\n (conditionChanged)=\"onCommandConditionChanged($event)\"\n ></praxis-visual-builder>\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.conditionJson.label', 'Condi\u00E7\u00E3o JSON Logic') }}</mat-label>\n <textarea\n matInput\n rows=\"5\"\n [(ngModel)]=\"commandRuleConditionJson\"\n [attr.aria-label]=\"tx('config.commandRules.conditionJson.ariaLabel', 'Condi\u00E7\u00E3o JSON Logic do comando condicional')\"\n ></textarea>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.globalAction.label', 'A\u00E7\u00E3o global') }}</mat-label>\n <mat-select [(ngModel)]=\"commandRuleActionId\" (selectionChange)=\"onCommandActionChange()\">\n @for (action of globalActionCatalog; track action) {\n <mat-option [value]=\"action.id\">\n {{ action.label || action.id }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ tx('config.commandRules.distinctBy.label', 'distinctBy') }}</mat-label>\n <input matInput [(ngModel)]=\"commandRuleDistinctBy\" [placeholder]=\"tx('config.commandRules.distinctBy.placeholder', 'ex.: idade')\" />\n </mat-form-field>\n\n @if (commandRuleActionSchema; as actionSchema) {\n <div\n class=\"command-rules-payload-fields command-rules-full\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.structuredPayload.title', 'Payload estruturado') }}</div>\n @if (actionSchema.editorMode !== 'surface-open') {\n @for (field of actionSchema.fields; track field) {\n @if (shouldShowCommandActionField(field)) {\n @if (field.type === 'toggle') {\n <mat-slide-toggle\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n >\n {{ field.label }}\n </mat-slide-toggle>\n } @else {\n <mat-form-field appearance=\"fill\">\n <mat-label>{{ field.label }}</mat-label>\n @if (field.type === 'textarea' || field.type === 'json') {\n <textarea\n matInput\n [rows]=\"field.rows || (field.type === 'json' ? 3 : 2)\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || (field.type === 'json' ? '{ }' : '')\"\n [required]=\"isCommandActionFieldRequired(field)\"\n ></textarea>\n } @else {\n @if (field.type === 'select') {\n <mat-select\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [required]=\"isCommandActionFieldRequired(field)\"\n >\n @for (option of field.options || []; track option) {\n <mat-option [value]=\"option.value\">\n {{ option.label }}\n </mat-option>\n }\n </mat-select>\n } @else {\n <input\n matInput\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [ngModel]=\"getCommandActionFieldValue(field)\"\n (ngModelChange)=\"onCommandActionFieldChange(field, $event)\"\n [ngModelOptions]=\"{ standalone: true }\"\n [placeholder]=\"field.placeholder || ''\"\n [required]=\"isCommandActionFieldRequired(field)\"\n />\n }\n }\n @if (field.hint) {\n <mat-hint>{{ field.hint }}</mat-hint>\n }\n @if (hasCommandActionFieldError(field.key)) {\n <mat-error>\n {{ getCommandActionFieldError(field.key) }}\n </mat-error>\n }\n @if (!hasCommandActionFieldError(field.key) && isCommandActionFieldMissing(field)) {\n <mat-error>\n {{ tx('config.commandRules.validation.requiredField', 'Campo obrigat\u00F3rio.') }}\n </mat-error>\n }\n </mat-form-field>\n }\n }\n }\n } @else {\n <praxis-surface-open-action-editor\n class=\"command-rules-surface-editor\"\n data-testid=\"form-command-rule-surface-open-editor\"\n [value]=\"commandRuleSurfaceOpenPayload\"\n hostKind=\"dynamic-form\"\n (valueChange)=\"onCommandSurfaceOpenPayloadChange($event)\"\n ></praxis-surface-open-action-editor>\n }\n </div>\n }\n\n <mat-form-field appearance=\"fill\" class=\"command-rules-full\">\n <mat-label>{{ tx('config.commandRules.advancedPayload.label', 'Payload JSON avan\u00E7ado') }}</mat-label>\n <textarea\n matInput\n rows=\"4\"\n [(ngModel)]=\"commandRulePayloadJson\"\n [attr.aria-label]=\"tx('config.commandRules.advancedPayload.ariaLabel', 'Payload JSON da a\u00E7\u00E3o global')\"\n ></textarea>\n </mat-form-field>\n\n <div class=\"command-rules-options\">\n <mat-slide-toggle [(ngModel)]=\"commandRuleDistinct\">{{ tx('config.commandRules.options.distinct', 'Evitar repeti\u00E7\u00E3o enquanto a condi\u00E7\u00E3o permanecer verdadeira') }}</mat-slide-toggle>\n <mat-slide-toggle [(ngModel)]=\"commandRuleRunOnInitialEvaluation\">{{ tx('config.commandRules.options.runOnInitialEvaluation', 'Executar tamb\u00E9m na avalia\u00E7\u00E3o inicial') }}</mat-slide-toggle>\n </div>\n\n @if (commandRuleAuthoringError) {\n <div class=\"preview-error command-rules-full\">\n <mat-icon aria-hidden=\"true\">warning</mat-icon>\n <span>{{ commandRuleAuthoringError }}</span>\n </div>\n }\n\n <div\n class=\"command-rule-preview command-rules-full\"\n [class.command-rule-preview--invalid]=\"commandRulePreview.state === 'invalid'\"\n data-testid=\"command-rule-preview\"\n >\n <div class=\"command-rules-section-title\">{{ tx('config.commandRules.preview.title', 'Preview do comando') }}</div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.mode', 'Modo') }}</span>\n <strong>{{ commandRulePreview.executionMode }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.action', 'A\u00E7\u00E3o') }}</span>\n <strong>{{ commandRulePreview.actionId || '\u2014' }}</strong>\n </div>\n <div class=\"command-rule-preview__row\">\n <span>{{ tx('config.commandRules.preview.policy', 'Policy') }}</span>\n <code>{{ commandRulePreview.policy | json }}</code>\n </div>\n @if (commandRulePreview.diagnostics.length) {\n <div class=\"command-rule-preview__diagnostics\">\n <mat-icon aria-hidden=\"true\">{{ commandRulePreview.state === 'invalid' ? 'warning' : 'visibility' }}</mat-icon>\n <span>{{ commandRulePreview.diagnostics[0] }}</span>\n </div>\n }\n </div>\n\n <div class=\"command-rules-actions\">\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"applyCommandRule()\">\n <mat-icon aria-hidden=\"true\">check</mat-icon>\n {{ tx('config.commandRules.actions.apply', 'Aplicar comando') }}\n </button>\n </div>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('cascades')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-cascatas\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.cascades.title', 'Depend\u00EAncias entre campos') }}</h3>\n <p class=\"text-caption\">{{ tx('config.cascades.subtitle', 'Configure cascatas e carregamento entre campos.') }}</p>\n </div>\n </div>\n <praxis-cascade-manager-tab [fields]=\"editedConfig.fieldMetadata || []\"\n (apply)=\"onCascadeApply($event)\"></praxis-cascade-manager-tab>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('messages')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-mensagens\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.messages.title', 'Mensagens e feedback') }}</h3>\n <p class=\"text-caption\">{{ tx('config.messages.subtitle', 'Padronize textos de sucesso, erro e confirma\u00E7\u00F5es.') }}</p>\n </div>\n </div>\n <praxis-messages-editor [config]=\"editedConfig\" (configChange)=\"onConfigChange($event)\"></praxis-messages-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('navigation')\">\n <div class=\"tab-content\" data-testid=\"config-tab-panel-navegacao\">\n <mat-card class=\"section-card\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.navigation.title', 'Navega\u00E7\u00E3o de retorno') }}</h3>\n <p class=\"text-caption\">{{ tx('config.navigation.subtitle', 'Defina o comportamento do bot\u00E3o Voltar em fluxos CRUD.') }}</p>\n </div>\n </div>\n <div class=\"form-grid\">\n <div class=\"form-row\">\n <mat-form-field appearance=\"fill\" class=\"w-100\">\n <mat-label>{{ tx('config.navigation.returnTo.label', 'Rota de retorno') }}</mat-label>\n <input matInput id=\"returnTo\" [(ngModel)]=\"backConfig!.returnTo\" (ngModelChange)=\"onBackConfigChange()\" [placeholder]=\"tx('config.navigation.returnTo.placeholder', '/funcionarios')\" />\n </mat-form-field>\n </div>\n <div class=\"form-row\">\n <mat-slide-toggle [(ngModel)]=\"backConfig!.confirmOnDirty\" (ngModelChange)=\"onBackConfigChange()\">\n {{ tx('config.navigation.confirmOnDirty.label', 'Confirmar ao sair com altera\u00E7\u00F5es') }}\n </mat-slide-toggle>\n </div>\n <div class=\"block-status\" [class.block-status--implicit]=\"!isBackConfigBlockPersisted()\">\n <strong>{{ tx('config.navigation.backConfig.label', 'Back Config') }}</strong>\n @if (isBackConfigBlockPersisted()) {\n <span>{{ tx('config.navigation.backConfig.persisted', '`contextSnapshot.backConfig` ser\u00E1 persistido no documento can\u00F4nico.') }}</span>\n } @else {\n {{ tx('config.navigation.backConfig.implicit', 'Bloco ausente no documento can\u00F4nico. Os valores exibidos s\u00E3o fallback visual e n\u00E3o ser\u00E3o salvos at\u00E9 voc\u00EA editar.') }}\n }\n </div>\n </div>\n <div class=\"section-help\">\n <span class=\"section-help__label\">{{ tx('config.navigation.note.label', 'Observa\u00E7\u00E3o:') }}</span>\n <button\n praxisIconButton=\"help_outline\"\n size=\"dense\"\n class=\"help-icon-button\"\n type=\"button\"\n [matTooltip]=\"tx('config.navigation.note.tooltip', 'Afeta o fluxo de navega\u00E7\u00E3o do CRUD e pode ser sobreposto por metadados do recurso.')\"\n matTooltipPosition=\"above\"\n >\n </button>\n </div>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n <mat-tab [label]=\"configTabLabel('json')\">\n <div class=\"tab-content json-tab-content\" data-testid=\"config-tab-panel-json\">\n <mat-card class=\"section-card section-card--json\">\n <mat-card-content>\n <div class=\"section-header\">\n <div>\n <h3>{{ tx('config.json.title', 'Configura\u00E7\u00E3o JSON') }}</h3>\n <p class=\"text-caption\">{{ tx('config.json.subtitle', 'Edi\u00E7\u00E3o avan\u00E7ada do documento can\u00F4nico de autoria do formul\u00E1rio.') }}</p>\n </div>\n </div>\n <form-json-config-editor [document]=\"jsonDocument\" (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\" (editorEvent)=\"onJsonEditorEvent($event)\">\n </form-json-config-editor>\n </mat-card-content>\n </mat-card>\n </div>\n </mat-tab>\n</mat-tab-group>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-width:0}.mobile-tab-selector{display:none;flex:0 0 auto;padding:8px 16px 0;background:var(--md-sys-color-surface)}.mobile-tab-selector__field{width:100%}.config-tabs{flex:1 1 auto;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs{display:flex;flex-direction:column}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-wrapper{flex:1;min-height:0;min-width:0}::ng-deep .mat-mdc-tab-group.config-tabs .mat-mdc-tab-body-content{height:100%;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;padding:0!important}.tab-content{padding:16px 20px 20px;flex:1;min-width:0;box-sizing:border-box}.json-tab-content{min-width:0;padding:12px 16px 16px}.section-card--json{display:flex;flex:1;min-height:calc(100vh - 180px);border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.section-card--json>mat-card-content{display:flex;flex:1;min-width:0;min-height:0;flex-direction:column}.section-card--json form-json-config-editor{display:block;flex:1;min-width:0;min-height:0}.form-row{display:block;margin-bottom:12px}.form-grid{display:grid;gap:12px}.section-help{display:inline-flex;align-items:center;gap:8px;color:var(--md-sys-color-on-surface-variant);font-size:12px}.section-help__label{font-weight:500}.grid-2-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:16px}.grid-2-cols--compact{gap:12px}.w-100{width:100%}.visual-builder-content{padding:0!important;height:100%;min-width:0;overflow-y:auto;overflow-x:hidden;display:flex;flex-direction:column;gap:16px}.visual-builder-content>praxis-visual-builder{flex:0 0 auto;min-width:0;min-height:clamp(360px,48vh,560px)}.visual-builder-content>praxis-rule-properties-panel{flex:0 0 auto;display:block;min-width:0;padding:0 16px 24px;box-sizing:border-box}.rules-diagnostics{flex:0 0 auto;display:grid;gap:10px;padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-low)}.rules-diagnostics--empty{color:var(--md-sys-color-on-surface-variant);font-size:12px;line-height:1.45}.rules-diagnostics__summary,.rules-diagnostics__list{display:flex;flex-wrap:wrap;gap:8px}.rules-diagnostics__pill{display:inline-flex;align-items:center;min-height:24px;padding:3px 9px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:12px;font-weight:600}.rules-diagnostics__pill--warn{background:color-mix(in srgb,var(--md-sys-color-tertiary-container) 72%,transparent);color:var(--md-sys-color-on-tertiary-container)}.rules-diagnostics__pill--error{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.rules-diagnostics__item{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;min-width:min(100%,280px);padding:8px 10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container)}.rules-diagnostics__item>div{display:grid;gap:2px;min-width:0}.rules-diagnostics__item strong{color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rules-diagnostics__item span{color:var(--md-sys-color-on-surface-variant);font-size:11px}.rules-diagnostics__actions{flex:0 0 auto;display:flex;align-items:center;gap:8px}.rules-diagnostics__details{display:grid;gap:2px;margin:4px 0 0;padding-left:16px;color:var(--md-sys-color-on-surface-variant);font-size:11px;line-height:1.35}.rules-diagnostics__details li{overflow-wrap:anywhere}.rules-diagnostics__item--warn{border-color:color-mix(in srgb,var(--md-sys-color-tertiary) 52%,var(--md-sys-color-outline-variant))}.rules-diagnostics__item--error{border-color:var(--md-sys-color-error)}.rules-diagnostics__status{font-weight:600;margin-top:1px}.rules-diagnostics__action{min-width:0;height:28px;padding:0 10px;border-radius:999px;font-size:12px;line-height:1}.rules-diagnostics__action mat-icon{width:16px;height:16px;margin:0 4px 0 0;font-size:16px}.json-field{width:100%}.presentation-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:20px;align-items:start}.presentation-controls{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:14px 18px}.control{display:flex;flex-direction:column}.control-span{grid-column:1/-1}.block-status{grid-column:1/-1;display:flex;gap:8px;align-items:flex-start;padding:10px 12px;border-radius:10px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 35%,transparent);color:var(--md-sys-color-on-surface);font-size:12px;line-height:1.45}.block-status strong{min-width:112px;font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant)}.block-status--implicit{background:color-mix(in srgb,var(--md-sys-color-surface-variant) 42%,transparent);border:1px dashed var(--md-sys-color-outline)}.block-status--readonly{margin-bottom:12px}.block-status code{font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:11px}.control__label{font-size:12px;color:var(--md-sys-color-on-surface-variant);margin-bottom:6px}.toggle-group{max-width:100%;flex-wrap:wrap}.control--inline{grid-column:1/-1;display:flex;gap:16px;align-items:center}.presentation-preview{min-width:0;order:-1}.preview-card{border:1px solid var(--md-sys-color-outline);border-radius:12px;padding:14px;background:var(--md-sys-color-surface-container)}.preview-row{display:flex;gap:8px;padding:6px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.preview-row:last-child{border-bottom:none}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.presentation-preview .praxis-presentation__label{color:var(--md-sys-color-on-surface-variant);font-size:var(--pfx-pres-label-size, 12px)}.presentation-preview .praxis-presentation__value{min-width:0;overflow-wrap:anywhere;font-size:var(--pfx-pres-value-size, 16px);color:var(--md-sys-color-on-surface)}.presentation-preview .presentation-mode.pres-density-cozy .preview-row{padding:6px 0}.presentation-preview .presentation-mode.pres-density-compact .preview-row,.presentation-preview .presentation-mode.pres-compact .preview-row{padding:2px 0}.presentation-preview .presentation-mode.pres-label-left .preview-row{display:grid;grid-template-columns:var(--pfx-pres-label-width, 140px) 1fr;align-items:baseline;column-gap:10px}.presentation-preview .presentation-mode.pres-label-left .praxis-presentation__label{margin:0;text-align:var(--pfx-pres-label-align, start)}.presentation-preview .presentation-mode .praxis-presentation__value{text-align:var(--pfx-pres-value-align, start)}.presentation-preview h4{margin:0 0 8px;color:var(--md-sys-color-on-surface);font-size:1rem}.section-card{border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);box-shadow:var(--md-sys-elevation-level1, none)}.section-header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.tab-content--dense{padding:12px 16px 16px}.tab-content--dense .section-header,.tab-content--dense .form-row{margin-bottom:8px}.section-header h3{margin:0;font-size:1.05rem;color:var(--md-sys-color-on-surface)}.text-caption{margin:6px 0 0;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.section-header--compact{margin-bottom:8px}.section-body{display:block}.section-body--flex{flex:1;min-height:0;display:flex;flex-direction:column}.builder-header{padding:12px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.builder-header h3{margin:0;font-size:1rem;color:var(--md-sys-color-on-surface)}.hint{margin:8px 0 0;padding:10px 12px;border-radius:10px;border:1px dashed var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface-variant)}.meta-card{display:grid;gap:6px;padding:10px 12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface)}.meta-row{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:.9rem;color:var(--md-sys-color-on-surface-variant)}.meta-row strong{color:var(--md-sys-color-on-surface);font-weight:600}.runtime-contract-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}.runtime-contract-field{display:grid;gap:6px;padding:12px;border-radius:10px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface)}.runtime-contract-label{font-size:12px;color:var(--md-sys-color-on-surface-variant)}.runtime-contract-code{display:block;font-family:var(--md-ref-typeface-mono, \"Courier New\", monospace);font-size:12px;line-height:1.45;color:var(--md-sys-color-on-surface);word-break:break-word;white-space:normal}.command-rules-card{margin:16px;min-width:0;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container)}.command-rules-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:12px;align-items:start;min-width:0}.command-rules-toolbar,.command-rules-options,.command-rules-actions{grid-column:1/-1;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.command-rules-select{min-width:min(320px,100%)}.command-rules-full{grid-column:1/-1}.command-rule-condition-builder{min-height:420px;overflow:hidden;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-payload-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:12px;min-width:0;padding:12px;border:1px dashed var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low)}.command-rules-section-title{grid-column:1/-1;font-size:12px;font-weight:600;color:var(--md-sys-color-on-surface-variant);text-transform:uppercase}.command-rules-surface-editor{grid-column:1/-1}.command-rule-preview{display:grid;gap:8px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.command-rule-preview--invalid{border-color:var(--md-sys-color-error)}.command-rule-preview__row{display:grid;grid-template-columns:minmax(96px,.35fr) minmax(0,1fr);gap:8px;align-items:start;min-width:0}.command-rule-preview__row span{color:var(--md-sys-color-on-surface-variant);font-size:12px;font-weight:600}.command-rule-preview__row strong,.command-rule-preview__row code{min-width:0;overflow-wrap:anywhere}.command-rule-preview__diagnostics{display:flex;gap:8px;align-items:flex-start;color:var(--md-sys-color-on-surface-variant)}@media(max-width:768px){.mobile-tab-selector{display:block}::ng-deep .mat-mdc-tab-group.config-tabs>.mat-mdc-tab-header{display:none}.tab-content{padding:12px}.json-tab-content{padding:8px}.section-card--json{min-height:auto}}.form-modes{display:flex;flex-direction:column;align-items:flex-start;gap:16px}.form-modes mat-button-toggle-group{max-width:100%;flex-wrap:wrap}.display-result{margin:0;padding-block:12px;color:var(--md-sys-color-on-surface);font:var(--md-sys-typescale-body-medium)}.presentation-preview .presentation-mode.pres-label-above .preview-row{flex-direction:column;gap:4px}.presentation-controls,.control{min-width:0}.block-status{flex-wrap:wrap}:host{container-type:inline-size}@container (min-width: 900px){.presentation-layout{grid-template-columns:minmax(0,1fr) minmax(280px,.8fr)}.presentation-preview{order:1;position:sticky;top:16px}}\n"] }]
31524
31632
  }], ctorParameters: () => [{ type: undefined, decorators: [{
31525
31633
  type: Inject,
31526
31634
  args: [ASYNC_CONFIG_STORAGE]
@@ -31791,6 +31899,7 @@ class PraxisFilterFormWidgetConfigEditor {
31791
31899
  if (!this.formEditor) {
31792
31900
  return;
31793
31901
  }
31902
+ this.formEditor.supportsPresentationSettings = false;
31794
31903
  this.initializeChildEditor();
31795
31904
  this.subscription.add(this.formEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
31796
31905
  this.subscription.add(this.formEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
@@ -32025,11 +32134,23 @@ class PraxisDynamicFormWidgetConfigEditor {
32025
32134
  isValid$ = new BehaviorSubject(true);
32026
32135
  isBusy$ = new BehaviorSubject(false);
32027
32136
  subscription = new Subscription();
32137
+ initialEditorConfig;
32138
+ cdr = (() => {
32139
+ try {
32140
+ return inject(ChangeDetectorRef, { optional: true });
32141
+ }
32142
+ catch {
32143
+ return null;
32144
+ }
32145
+ })();
32028
32146
  ngAfterViewInit() {
32029
32147
  if (!this.formEditor) {
32030
32148
  return;
32031
32149
  }
32032
32150
  this.initializeChildEditor();
32151
+ // Finish child template normalization before capturing the authoring baseline.
32152
+ this.cdr?.detectChanges();
32153
+ this.initialEditorConfig = JSON.stringify(parseLegacyOrDynamicFormDocument(this.formEditor.getSettingsValue?.() ?? this.createDocumentFromInputs()).config);
32033
32154
  this.subscription.add(this.formEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
32034
32155
  this.subscription.add(this.formEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
32035
32156
  this.subscription.add(this.formEditor.isBusy$.subscribe((value) => this.isBusy$.next(value)));
@@ -32063,8 +32184,12 @@ class PraxisDynamicFormWidgetConfigEditor {
32063
32184
  return {
32064
32185
  inputs: {
32065
32186
  ...(this.inputs ?? {}),
32066
- config: document.config,
32067
- mode: document.bindings?.mode ?? this.inputs?.mode ?? 'create',
32187
+ // Changing only mode/schema preferences must not pin an empty schema projection.
32188
+ config: this.initialEditorConfig === JSON.stringify(document.config)
32189
+ ? this.inputs?.config : document.config,
32190
+ mode: document.bindings?.mode ?? 'create',
32191
+ presentationModeGlobal: document.bindings?.presentationModeGlobal ?? null,
32192
+ presentation: document.contextSnapshot?.presentation ?? null,
32068
32193
  formId: this.inputs?.formId ?? this.widgetKey,
32069
32194
  componentInstanceId: this.inputs?.componentInstanceId ?? this.widgetKey,
32070
32195
  backConfig: document.contextSnapshot?.backConfig ?? this.inputs?.backConfig,
@@ -32091,9 +32216,11 @@ class PraxisDynamicFormWidgetConfigEditor {
32091
32216
  config: this.inputs?.config ?? { sections: [], fieldMetadata: [] },
32092
32217
  bindings: {
32093
32218
  mode: this.inputs?.mode ?? 'create',
32219
+ presentationModeGlobal: this.inputs?.presentationModeGlobal,
32094
32220
  },
32095
32221
  contextSnapshot: {
32096
32222
  backConfig: this.inputs?.backConfig,
32223
+ presentation: this.inputs?.presentation,
32097
32224
  schemaPrefs,
32098
32225
  },
32099
32226
  });
@@ -32102,22 +32229,18 @@ class PraxisDynamicFormWidgetConfigEditor {
32102
32229
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PraxisDynamicFormWidgetConfigEditor, isStandalone: true, selector: "praxis-dynamic-form-widget-config-editor", inputs: { inputs: "inputs", widgetKey: "widgetKey" }, viewQueries: [{ propertyName: "formEditor", first: true, predicate: ["formEditor"], descendants: true }], ngImport: i0, template: `
32103
32230
  <section data-testid="dynamic-form-widget-config-editor">
32104
32231
  <praxis-dynamic-form-config-editor #formEditor />
32232
+ <p class="widget-save-hint">{{ formEditor.tx('config.general.pageSaveHint') }}</p>
32105
32233
  </section>
32106
- `, isInline: true, dependencies: [{ kind: "component", type: PraxisDynamicFormConfigEditor, selector: "praxis-dynamic-form-config-editor" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
32234
+ `, isInline: true, styles: [".widget-save-hint{margin:12px 20px;color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-body-small)}\n"], dependencies: [{ kind: "component", type: PraxisDynamicFormConfigEditor, selector: "praxis-dynamic-form-config-editor" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
32107
32235
  }
32108
32236
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicFormWidgetConfigEditor, decorators: [{
32109
32237
  type: Component,
32110
- args: [{
32111
- selector: 'praxis-dynamic-form-widget-config-editor',
32112
- standalone: true,
32113
- imports: [PraxisDynamicFormConfigEditor],
32114
- template: `
32238
+ args: [{ selector: 'praxis-dynamic-form-widget-config-editor', standalone: true, imports: [PraxisDynamicFormConfigEditor], template: `
32115
32239
  <section data-testid="dynamic-form-widget-config-editor">
32116
32240
  <praxis-dynamic-form-config-editor #formEditor />
32241
+ <p class="widget-save-hint">{{ formEditor.tx('config.general.pageSaveHint') }}</p>
32117
32242
  </section>
32118
- `,
32119
- changeDetection: ChangeDetectionStrategy.OnPush,
32120
- }]
32243
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".widget-save-hint{margin:12px 20px;color:var(--md-sys-color-on-surface-variant);font:var(--md-sys-typescale-body-small)}\n"] }]
32121
32244
  }], propDecorators: { inputs: [{
32122
32245
  type: Input
32123
32246
  }], widgetKey: [{
@@ -32396,7 +32519,8 @@ const PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA = {
32396
32519
  { name: 'autoOpenSettingsOnOutdated', type: 'boolean', default: false, description: 'Abre editor automaticamente quando schema esta desatualizado' },
32397
32520
  { name: 'readonlyModeGlobal', type: 'boolean | null', description: 'Trava global para campos em modo somente-leitura' },
32398
32521
  { name: 'disabledModeGlobal', type: 'boolean | null', description: 'Trava global para desabilitar campos' },
32399
- { name: 'presentationModeGlobal', type: 'boolean | null', description: 'Modo de apresentacao (sem edicao)' },
32522
+ { name: 'presentation', type: 'DynamicFormPresentationSnapshot | null', description: 'Projeção de contextSnapshot.presentation para hosts e Page Builder. Tamanhos em pixels; null remove ajustes explícitos. Não altera mode nem presentationModeGlobal.' },
32523
+ { name: 'presentationModeGlobal', type: 'boolean | null', description: 'Preferência de exibição, também editável em Geral: true apresenta em view, false força campos, null segue layoutPolicy. Persiste em bindings.presentationModeGlobal.' },
32400
32524
  { name: 'fieldIconPolicy', type: "'all' | 'presentation-only' | 'none'", default: 'all', description: 'Controla se icones prefix/suffix de campos aparecem em controles tradicionais ou apenas em apresentacao.' },
32401
32525
  { name: 'visibleGlobal', type: 'boolean | null', description: 'Visibilidade global' },
32402
32526
  { name: 'customEndpoints', type: 'EndpointConfig', description: 'Endpoints customizados para operacoes CRUD' },
@@ -32410,7 +32534,7 @@ const PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA = {
32410
32534
  name: 'configPatchChange',
32411
32535
  type: 'DynamicFormConfigPatchChangeEvent',
32412
32536
  label: 'Patch persistivel de configuracao',
32413
- description: 'Emite inputPatch.config quando a configuracao autorada do formulario muda, para hosts persistirem inputs.config sem alterar o payload legado de configChange.',
32537
+ description: 'Emite inputPatch parcial com config, resourcePath, mode, presentationModeGlobal e/ou presentation para hosts persistirem apenas as entradas autoradas presentes, incluindo conexao rapida, sem alterar o payload legado de configChange.',
32414
32538
  },
32415
32539
  { name: 'formReady', type: 'FormReadyEvent', label: 'Form pronto', description: 'Emite quando o formulario esta pronto' },
32416
32540
  { name: 'valueChange', type: 'FormValueChangeEvent', label: 'Valor alterado', description: 'Emite quando valores mudam' },
@@ -33087,7 +33211,7 @@ class Ergadm00034CompactPresentationExampleComponent {
33087
33211
  corporatePresentationConfig = buildCorporatePresentationFormatGalleryConfig(this.dynamicLayout);
33088
33212
  corporatePresentationInitialValue = this.corporatePresentationExample.initialValue;
33089
33213
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: Ergadm00034CompactPresentationExampleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
33090
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: Ergadm00034CompactPresentationExampleComponent, isStandalone: true, selector: "praxis-ergadm00034-compact-presentation-example", ngImport: i0, template: "<mat-card class=\"legacy-presentation-card\" data-testid=\"ergadm00034-compact-fixture\">\n <div class=\"legacy-presentation-header\">\n <div>\n <p class=\"examples-eyebrow\">Exemplo visual da lib</p>\n <h2>{{ legacyFrequencyExample.title }}</h2>\n <p>\n Fixture visual representativo de <code>{{ legacyFrequencyExample.resourcePath }}</code>:\n cinco registros densos e detalhe gerado por <code>x-ui.group</code>, <code>order</code>\n e <code>width</code>, sem declarar <code>FormConfig.sections</code> no host.\n </p>\n </div>\n <div class=\"legacy-presentation-badge\">\n <mat-icon aria-hidden=\"true\">view_compact</mat-icon>\n <span>compactPresentation</span>\n </div>\n </div>\n\n <div class=\"legacy-workbench\">\n <section class=\"legacy-records-panel\" aria-labelledby=\"legacy-records-title\">\n <div class=\"legacy-panel-heading\">\n <div>\n <h3 id=\"legacy-records-title\">C\u00F3digos de frequ\u00EAncia</h3>\n <p>5 registros carregados</p>\n </div>\n <span class=\"legacy-count-chip\">fixture local</span>\n </div>\n\n <div class=\"legacy-table-wrap\">\n <table class=\"legacy-record-table\" aria-label=\"C\u00F3digos de frequ\u00EAncia\">\n <thead>\n <tr>\n <th scope=\"col\">Tipo</th>\n <th scope=\"col\">C\u00F3digo</th>\n <th scope=\"col\">Nome</th>\n <th scope=\"col\">Preench.</th>\n <th scope=\"col\">Marcador</th>\n </tr>\n </thead>\n <tbody>\n @for (row of legacyFrequencyRows; track row.codigo) {\n <tr [class.is-selected]=\"row.selected\">\n <td>{{ row.tipo }}</td>\n <td><strong>{{ row.codigo }}</strong></td>\n <td>{{ row.nome }}</td>\n <td>{{ row.preenchimento }}</td>\n <td>{{ row.marcador }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </section>\n\n <section class=\"legacy-detail-panel\" aria-labelledby=\"legacy-detail-title\">\n <div class=\"legacy-detail-toolbar\">\n <div>\n <p class=\"legacy-detail-kicker\">Registro selecionado</p>\n <h3 id=\"legacy-detail-title\">AFA - Afastamento abonado</h3>\n </div>\n <div class=\"legacy-detail-actions\" aria-label=\"A\u00E7\u00F5es do registro\">\n <button type=\"button\" aria-label=\"Novo c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n </button>\n <button type=\"button\" aria-label=\"Editar c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n </div>\n </div>\n\n <div class=\"legacy-detail-tabs\" aria-label=\"Abas do detalhe\">\n <button type=\"button\" class=\"is-active\">\n <mat-icon aria-hidden=\"true\">fact_check</mat-icon>\n <span>Detalhes</span>\n </button>\n <button type=\"button\">\n <mat-icon aria-hidden=\"true\">gavel</mat-icon>\n <span>Documentos legais</span>\n </button>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact legacy-frequency-form\"\n data-testid=\"ergadm00034-detail-form\"\n formId=\"legacy-frequency-compact-presentation-demo\"\n [config]=\"legacyFrequencyPresentationConfig\"\n [initialValue]=\"legacyFrequencyInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n </div>\n\n <section class=\"corporate-format-gallery\" data-testid=\"corporate-format-gallery\">\n <div class=\"corporate-gallery-heading\">\n <div>\n <p class=\"examples-eyebrow\">Valida\u00E7\u00E3o de apresenta\u00E7\u00E3o</p>\n <h2>{{ corporatePresentationExample.title }}</h2>\n <p>\n Fixture de <code>{{ corporatePresentationExample.resourcePath }}</code> para validar\n datas, moedas, percentuais, quantidades, documentos, listas e status em telas densas.\n </p>\n </div>\n <div class=\"corporate-kpi-strip\" aria-label=\"Resumo financeiro\">\n <span>\n <strong>R$ 1,38 mi</strong>\n <small>valor bruto</small>\n </span>\n <span>\n <strong>18,45%</strong>\n <small>margem</small>\n </span>\n <span>\n <strong>42</strong>\n <small>itens</small>\n </span>\n </div>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact corporate-format-form\"\n data-testid=\"corporate-format-detail-form\"\n formId=\"corporate-format-gallery-demo\"\n [config]=\"corporatePresentationConfig\"\n [initialValue]=\"corporatePresentationInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n</mat-card>\n", styles: [":host{--pdx-ergadm-bg: var(--mat-sys-surface, var(--md-sys-color-surface, #ffffff));--pdx-ergadm-surface-strong: color-mix( in srgb, var(--mat-sys-surface-container-high, var(--md-sys-color-surface-container-high, #eef3f1)) 90%, var(--pdx-ergadm-bg) );--pdx-ergadm-border: color-mix( in srgb, var(--mat-sys-outline-variant, var(--md-sys-color-outline-variant, #c6d0cb)) 76%, transparent );--pdx-ergadm-text: var(--mat-sys-on-surface, var(--md-sys-color-on-surface, #17221d));--pdx-ergadm-text-muted: var( --mat-sys-on-surface-variant, var(--md-sys-color-on-surface-variant, #53625c) );--pdx-ergadm-primary: var(--mat-sys-primary, var(--md-sys-color-primary, #0f766e));--pdx-ergadm-primary-strong: color-mix(in srgb, var(--pdx-ergadm-primary) 82%, black);--pdx-ergadm-primary-soft: color-mix(in srgb, var(--pdx-ergadm-primary) 14%, transparent);--pdx-ergadm-chip-bg: color-mix( in srgb, var(--mat-sys-primary-container, var(--md-sys-color-primary-container, #dcefeb)) 74%, var(--pdx-ergadm-bg) );--pdx-ergadm-chip-text: var( --mat-sys-on-primary-container, var(--md-sys-color-on-primary-container, #123932) );--pdx-ergadm-shadow-soft: 0 18px 36px rgba(15, 23, 42, .06);display:block;min-width:0;color:var(--pdx-ergadm-text)}.legacy-presentation-card{padding:22px;border-radius:20px;border:1px solid var(--pdx-ergadm-border);background:linear-gradient(180deg,color-mix(in srgb,var(--pdx-ergadm-surface-strong) 86%,var(--pdx-ergadm-bg)) 0%,var(--pdx-ergadm-bg) 100%);box-shadow:var(--pdx-ergadm-shadow-soft)}.legacy-presentation-header{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:14px}.examples-eyebrow{margin:0;text-transform:uppercase;letter-spacing:.18em;font-size:.76rem;font-weight:800;color:color-mix(in srgb,var(--pdx-ergadm-primary) 84%,var(--pdx-ergadm-text))}.legacy-presentation-header h2{margin:6px 0 8px;font-size:clamp(1.18rem,1.6vw,1.48rem);line-height:1.14}.legacy-presentation-header p{margin:0;max-width:76ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.legacy-presentation-badge{display:inline-flex;align-items:center;gap:8px;flex:0 0 auto;padding:8px 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-chip-bg);color:var(--pdx-ergadm-chip-text);font-size:.82rem;font-weight:800}.legacy-workbench{display:grid;grid-template-columns:minmax(360px,.44fr) minmax(0,1fr);gap:14px;align-items:start}.legacy-records-panel,.legacy-detail-panel{min-width:0;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 88%,var(--pdx-ergadm-surface-strong))}.legacy-records-panel{overflow:hidden}.legacy-detail-panel{padding:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.legacy-panel-heading{padding:12px 14px 10px;border-bottom:1px solid var(--pdx-ergadm-border)}.legacy-panel-heading h3,.legacy-detail-toolbar h3{margin:0;font-size:.98rem;line-height:1.25}.legacy-panel-heading p,.legacy-detail-kicker{margin:3px 0 0;color:var(--pdx-ergadm-text-muted);font-size:.76rem;line-height:1.35}.legacy-count-chip{flex:0 0 auto;padding:5px 8px;border-radius:999px;background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong);font-size:.68rem;font-weight:800;text-transform:uppercase}.legacy-table-wrap{overflow-x:auto}.legacy-record-table{width:100%;min-width:500px;border-collapse:collapse;font-size:.78rem;line-height:1.25}.legacy-record-table th,.legacy-record-table td{padding:8px 10px;text-align:left;white-space:nowrap;border-bottom:1px solid color-mix(in srgb,var(--pdx-ergadm-border) 78%,transparent)}.legacy-record-table th{color:var(--pdx-ergadm-text-muted);font-size:.66rem;font-weight:800;text-transform:uppercase}.legacy-record-table td:nth-child(3){max-width:190px;overflow:hidden;text-overflow:ellipsis}.legacy-record-table tr:last-child td{border-bottom:0}.legacy-record-table tr.is-selected td{background:color-mix(in srgb,var(--pdx-ergadm-primary) 11%,transparent)}.legacy-detail-actions{display:inline-flex;gap:6px;flex:0 0 auto}.legacy-detail-actions button{display:inline-grid;place-items:center;width:32px;height:32px;border:1px solid var(--pdx-ergadm-border);border-radius:8px;background:var(--pdx-ergadm-bg);color:var(--pdx-ergadm-primary-strong);cursor:default}.legacy-detail-actions mat-icon{width:18px;height:18px;font-size:18px}.legacy-detail-tabs{display:flex;gap:6px;margin:12px 0;padding-bottom:8px;border-bottom:1px solid var(--pdx-ergadm-border);overflow-x:auto}.legacy-detail-tabs button{display:inline-flex;align-items:center;gap:6px;min-height:30px;padding:5px 9px;border:1px solid transparent;border-radius:999px;background:transparent;color:var(--pdx-ergadm-text-muted);font:inherit;font-size:.78rem;font-weight:700;white-space:nowrap}.legacy-detail-tabs button.is-active{border-color:color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong)}.legacy-detail-tabs mat-icon{width:16px;height:16px;font-size:16px}.legacy-frequency-form{--pdx-presentation-label-width: 116px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;--pdx-presentation-flag-height: 20px;--pdx-presentation-flag-padding: 0 7px;display:block}.corporate-format-gallery{margin-top:18px;padding-top:18px;border-top:1px solid var(--pdx-ergadm-border)}.corporate-gallery-heading{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,.34fr);gap:16px;align-items:start;margin-bottom:12px}.corporate-gallery-heading h2{margin:6px 0 8px;font-size:clamp(1.08rem,1.35vw,1.32rem);line-height:1.16}.corporate-gallery-heading p{margin:0;max-width:82ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.corporate-kpi-strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.corporate-kpi-strip span{min-width:0;padding:10px;border:1px solid var(--pdx-ergadm-border);border-radius:12px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 86%,var(--pdx-ergadm-primary-soft))}.corporate-kpi-strip strong,.corporate-kpi-strip small{display:block;min-width:0;overflow-wrap:anywhere}.corporate-kpi-strip strong{color:var(--pdx-ergadm-primary-strong);font-size:.96rem;line-height:1.2}.corporate-kpi-strip small{margin-top:3px;color:var(--pdx-ergadm-text-muted);font-size:.68rem;font-weight:700;text-transform:uppercase}.corporate-format-form{--pdx-presentation-label-width: 132px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;display:block;padding:12px;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 90%,var(--pdx-ergadm-surface-strong))}@media(max-width:960px){.legacy-workbench,.corporate-gallery-heading{grid-template-columns:1fr}}@media(max-width:720px){.legacy-presentation-card{padding:18px;border-radius:20px}.legacy-presentation-header{display:grid}.legacy-presentation-badge{width:fit-content}.legacy-records-panel,.legacy-detail-panel{border-radius:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:grid}.legacy-record-table{min-width:460px}.legacy-frequency-form{--pdx-presentation-label-width: 104px}.corporate-kpi-strip{grid-template-columns:1fr}.corporate-format-form{--pdx-presentation-label-width: 104px;padding:10px}}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i7$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "emptyState", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "submitResourceVersionTargetResourceKey", "submitResourceVersionTargetIdField", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "payloadPreviewChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
33214
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: Ergadm00034CompactPresentationExampleComponent, isStandalone: true, selector: "praxis-ergadm00034-compact-presentation-example", ngImport: i0, template: "<mat-card class=\"legacy-presentation-card\" data-testid=\"ergadm00034-compact-fixture\">\n <div class=\"legacy-presentation-header\">\n <div>\n <p class=\"examples-eyebrow\">Exemplo visual da lib</p>\n <h2>{{ legacyFrequencyExample.title }}</h2>\n <p>\n Fixture visual representativo de <code>{{ legacyFrequencyExample.resourcePath }}</code>:\n cinco registros densos e detalhe gerado por <code>x-ui.group</code>, <code>order</code>\n e <code>width</code>, sem declarar <code>FormConfig.sections</code> no host.\n </p>\n </div>\n <div class=\"legacy-presentation-badge\">\n <mat-icon aria-hidden=\"true\">view_compact</mat-icon>\n <span>compactPresentation</span>\n </div>\n </div>\n\n <div class=\"legacy-workbench\">\n <section class=\"legacy-records-panel\" aria-labelledby=\"legacy-records-title\">\n <div class=\"legacy-panel-heading\">\n <div>\n <h3 id=\"legacy-records-title\">C\u00F3digos de frequ\u00EAncia</h3>\n <p>5 registros carregados</p>\n </div>\n <span class=\"legacy-count-chip\">fixture local</span>\n </div>\n\n <div class=\"legacy-table-wrap\">\n <table class=\"legacy-record-table\" aria-label=\"C\u00F3digos de frequ\u00EAncia\">\n <thead>\n <tr>\n <th scope=\"col\">Tipo</th>\n <th scope=\"col\">C\u00F3digo</th>\n <th scope=\"col\">Nome</th>\n <th scope=\"col\">Preench.</th>\n <th scope=\"col\">Marcador</th>\n </tr>\n </thead>\n <tbody>\n @for (row of legacyFrequencyRows; track row.codigo) {\n <tr [class.is-selected]=\"row.selected\">\n <td>{{ row.tipo }}</td>\n <td><strong>{{ row.codigo }}</strong></td>\n <td>{{ row.nome }}</td>\n <td>{{ row.preenchimento }}</td>\n <td>{{ row.marcador }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </section>\n\n <section class=\"legacy-detail-panel\" aria-labelledby=\"legacy-detail-title\">\n <div class=\"legacy-detail-toolbar\">\n <div>\n <p class=\"legacy-detail-kicker\">Registro selecionado</p>\n <h3 id=\"legacy-detail-title\">AFA - Afastamento abonado</h3>\n </div>\n <div class=\"legacy-detail-actions\" aria-label=\"A\u00E7\u00F5es do registro\">\n <button type=\"button\" aria-label=\"Novo c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">add</mat-icon>\n </button>\n <button type=\"button\" aria-label=\"Editar c\u00F3digo de frequ\u00EAncia\">\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n </div>\n </div>\n\n <div class=\"legacy-detail-tabs\" aria-label=\"Abas do detalhe\">\n <button type=\"button\" class=\"is-active\">\n <mat-icon aria-hidden=\"true\">fact_check</mat-icon>\n <span>Detalhes</span>\n </button>\n <button type=\"button\">\n <mat-icon aria-hidden=\"true\">gavel</mat-icon>\n <span>Documentos legais</span>\n </button>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact legacy-frequency-form\"\n data-testid=\"ergadm00034-detail-form\"\n formId=\"legacy-frequency-compact-presentation-demo\"\n [config]=\"legacyFrequencyPresentationConfig\"\n [initialValue]=\"legacyFrequencyInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n </div>\n\n <section class=\"corporate-format-gallery\" data-testid=\"corporate-format-gallery\">\n <div class=\"corporate-gallery-heading\">\n <div>\n <p class=\"examples-eyebrow\">Valida\u00E7\u00E3o de apresenta\u00E7\u00E3o</p>\n <h2>{{ corporatePresentationExample.title }}</h2>\n <p>\n Fixture de <code>{{ corporatePresentationExample.resourcePath }}</code> para validar\n datas, moedas, percentuais, quantidades, documentos, listas e status em telas densas.\n </p>\n </div>\n <div class=\"corporate-kpi-strip\" aria-label=\"Resumo financeiro\">\n <span>\n <strong>R$ 1,38 mi</strong>\n <small>valor bruto</small>\n </span>\n <span>\n <strong>18,45%</strong>\n <small>margem</small>\n </span>\n <span>\n <strong>42</strong>\n <small>itens</small>\n </span>\n </div>\n </div>\n\n <praxis-dynamic-form\n class=\"presentation-mode pres-label-left pres-density-compact corporate-format-form\"\n data-testid=\"corporate-format-detail-form\"\n formId=\"corporate-format-gallery-demo\"\n [config]=\"corporatePresentationConfig\"\n [initialValue]=\"corporatePresentationInitialValue\"\n mode=\"view\"\n [presentationModeGlobal]=\"true\"\n [enableCustomization]=\"false\"\n [showAiAssistant]=\"false\"\n ></praxis-dynamic-form>\n </section>\n</mat-card>\n", styles: [":host{--pdx-ergadm-bg: var(--mat-sys-surface, var(--md-sys-color-surface, #ffffff));--pdx-ergadm-surface-strong: color-mix( in srgb, var(--mat-sys-surface-container-high, var(--md-sys-color-surface-container-high, #eef3f1)) 90%, var(--pdx-ergadm-bg) );--pdx-ergadm-border: color-mix( in srgb, var(--mat-sys-outline-variant, var(--md-sys-color-outline-variant, #c6d0cb)) 76%, transparent );--pdx-ergadm-text: var(--mat-sys-on-surface, var(--md-sys-color-on-surface, #17221d));--pdx-ergadm-text-muted: var( --mat-sys-on-surface-variant, var(--md-sys-color-on-surface-variant, #53625c) );--pdx-ergadm-primary: var(--mat-sys-primary, var(--md-sys-color-primary, #0f766e));--pdx-ergadm-primary-strong: color-mix(in srgb, var(--pdx-ergadm-primary) 82%, black);--pdx-ergadm-primary-soft: color-mix(in srgb, var(--pdx-ergadm-primary) 14%, transparent);--pdx-ergadm-chip-bg: color-mix( in srgb, var(--mat-sys-primary-container, var(--md-sys-color-primary-container, #dcefeb)) 74%, var(--pdx-ergadm-bg) );--pdx-ergadm-chip-text: var( --mat-sys-on-primary-container, var(--md-sys-color-on-primary-container, #123932) );--pdx-ergadm-shadow-soft: 0 18px 36px rgba(15, 23, 42, .06);display:block;min-width:0;color:var(--pdx-ergadm-text)}.legacy-presentation-card{padding:22px;border-radius:20px;border:1px solid var(--pdx-ergadm-border);background:linear-gradient(180deg,color-mix(in srgb,var(--pdx-ergadm-surface-strong) 86%,var(--pdx-ergadm-bg)) 0%,var(--pdx-ergadm-bg) 100%);box-shadow:var(--pdx-ergadm-shadow-soft)}.legacy-presentation-header{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:14px}.examples-eyebrow{margin:0;text-transform:uppercase;letter-spacing:.18em;font-size:.76rem;font-weight:800;color:color-mix(in srgb,var(--pdx-ergadm-primary) 84%,var(--pdx-ergadm-text))}.legacy-presentation-header h2{margin:6px 0 8px;font-size:clamp(1.18rem,1.6vw,1.48rem);line-height:1.14}.legacy-presentation-header p{margin:0;max-width:76ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.legacy-presentation-badge{display:inline-flex;align-items:center;gap:8px;flex:0 0 auto;padding:8px 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-chip-bg);color:var(--pdx-ergadm-chip-text);font-size:.82rem;font-weight:800}.legacy-workbench{display:grid;grid-template-columns:minmax(360px,.44fr) minmax(0,1fr);gap:14px;align-items:start}.legacy-records-panel,.legacy-detail-panel{min-width:0;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 88%,var(--pdx-ergadm-surface-strong))}.legacy-records-panel{overflow:hidden}.legacy-detail-panel{padding:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.legacy-panel-heading{padding:12px 14px 10px;border-bottom:1px solid var(--pdx-ergadm-border)}.legacy-panel-heading h3,.legacy-detail-toolbar h3{margin:0;font-size:.98rem;line-height:1.25}.legacy-panel-heading p,.legacy-detail-kicker{margin:3px 0 0;color:var(--pdx-ergadm-text-muted);font-size:.76rem;line-height:1.35}.legacy-count-chip{flex:0 0 auto;padding:5px 8px;border-radius:999px;background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong);font-size:.68rem;font-weight:800;text-transform:uppercase}.legacy-table-wrap{overflow-x:auto}.legacy-record-table{width:100%;min-width:500px;border-collapse:collapse;font-size:.78rem;line-height:1.25}.legacy-record-table th,.legacy-record-table td{padding:8px 10px;text-align:left;white-space:nowrap;border-bottom:1px solid color-mix(in srgb,var(--pdx-ergadm-border) 78%,transparent)}.legacy-record-table th{color:var(--pdx-ergadm-text-muted);font-size:.66rem;font-weight:800;text-transform:uppercase}.legacy-record-table td:nth-child(3){max-width:190px;overflow:hidden;text-overflow:ellipsis}.legacy-record-table tr:last-child td{border-bottom:0}.legacy-record-table tr.is-selected td{background:color-mix(in srgb,var(--pdx-ergadm-primary) 11%,transparent)}.legacy-detail-actions{display:inline-flex;gap:6px;flex:0 0 auto}.legacy-detail-actions button{display:inline-grid;place-items:center;width:32px;height:32px;border:1px solid var(--pdx-ergadm-border);border-radius:8px;background:var(--pdx-ergadm-bg);color:var(--pdx-ergadm-primary-strong);cursor:default}.legacy-detail-actions mat-icon{width:18px;height:18px;font-size:18px}.legacy-detail-tabs{display:flex;gap:6px;margin:12px 0;padding-bottom:8px;border-bottom:1px solid var(--pdx-ergadm-border);overflow-x:auto}.legacy-detail-tabs button{display:inline-flex;align-items:center;gap:6px;min-height:30px;padding:5px 9px;border:1px solid transparent;border-radius:999px;background:transparent;color:var(--pdx-ergadm-text-muted);font:inherit;font-size:.78rem;font-weight:700;white-space:nowrap}.legacy-detail-tabs button.is-active{border-color:color-mix(in srgb,var(--pdx-ergadm-primary) 18%,transparent);background:var(--pdx-ergadm-primary-soft);color:var(--pdx-ergadm-primary-strong)}.legacy-detail-tabs mat-icon{width:16px;height:16px;font-size:16px}.legacy-frequency-form{--pdx-presentation-label-width: 116px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;--pdx-presentation-flag-height: 20px;--pdx-presentation-flag-padding: 0 7px;display:block}.corporate-format-gallery{margin-top:18px;padding-top:18px;border-top:1px solid var(--pdx-ergadm-border)}.corporate-gallery-heading{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,.34fr);gap:16px;align-items:start;margin-bottom:12px}.corporate-gallery-heading h2{margin:6px 0 8px;font-size:clamp(1.08rem,1.35vw,1.32rem);line-height:1.16}.corporate-gallery-heading p{margin:0;max-width:82ch;color:var(--pdx-ergadm-text-muted);line-height:1.55}.corporate-kpi-strip{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.corporate-kpi-strip span{min-width:0;padding:10px;border:1px solid var(--pdx-ergadm-border);border-radius:12px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 86%,var(--pdx-ergadm-primary-soft))}.corporate-kpi-strip strong,.corporate-kpi-strip small{display:block;min-width:0;overflow-wrap:anywhere}.corporate-kpi-strip strong{color:var(--pdx-ergadm-primary-strong);font-size:.96rem;line-height:1.2}.corporate-kpi-strip small{margin-top:3px;color:var(--pdx-ergadm-text-muted);font-size:.68rem;font-weight:700;text-transform:uppercase}.corporate-format-form{--pdx-presentation-label-width: 132px;--pdx-presentation-label-size: .7rem;--pdx-presentation-value-size: .9rem;display:block;padding:12px;border:1px solid var(--pdx-ergadm-border);border-radius:14px;background:color-mix(in srgb,var(--pdx-ergadm-bg) 90%,var(--pdx-ergadm-surface-strong))}@media(max-width:960px){.legacy-workbench,.corporate-gallery-heading{grid-template-columns:1fr}}@media(max-width:720px){.legacy-presentation-card{padding:18px;border-radius:20px}.legacy-presentation-header{display:grid}.legacy-presentation-badge{width:fit-content}.legacy-records-panel,.legacy-detail-panel{border-radius:12px}.legacy-panel-heading,.legacy-detail-toolbar{display:grid}.legacy-record-table{min-width:460px}.legacy-frequency-form{--pdx-presentation-label-width: 104px}.corporate-kpi-strip{grid-template-columns:1fr}.corporate-format-form{--pdx-presentation-label-width: 104px;padding:10px}}\n"], dependencies: [{ kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i7$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisDynamicForm, selector: "praxis-dynamic-form", inputs: ["resourcePath", "resourceId", "initialValue", "emptyState", "editorialContext", "mode", "config", "actions", "schemaSource", "schemaUrl", "readUrl", "submitUrl", "submitMethod", "submitIdempotencyKey", "submitCorrelationId", "submitResourceVersion", "submitResourceVersionTargetResourceKey", "submitResourceVersionTargetIdField", "responseSchemaUrl", "apiEndpointKey", "apiUrlEntry", "enableCustomization", "showAiAssistant", "formId", "componentInstanceId", "configPersistenceStrategy", "layout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "presentation", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "payloadPreviewChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
33091
33215
  }
33092
33216
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: Ergadm00034CompactPresentationExampleComponent, decorators: [{
33093
33217
  type: Component,