@praxisui/dynamic-form 10.0.0-rc.3 → 10.0.0-rc.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import { Injectable, EventEmitter, inject, HostListener, Output, Input, Componen
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';
6
- import { HttpHeaders, HttpContext } from '@angular/common/http';
6
+ import { HttpHeaders, HttpErrorResponse, HttpContext } from '@angular/common/http';
7
7
  import * as i1$3 from '@angular/forms';
8
8
  import { ReactiveFormsModule, FormsModule, FormGroup, Validators } from '@angular/forms';
9
9
  import * as i4 from '@angular/material/icon';
@@ -23,9 +23,9 @@ import { MatBadgeModule } from '@angular/material/badge';
23
23
  import { map, Subscription, merge, of, timer, NEVER, EMPTY, defer, TimeoutError, Subject, firstValueFrom, BehaviorSubject, throwError, combineLatest, Observable, race, from, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs';
24
24
  import { filter, map as map$1, switchMap, take, timeout, throwIfEmpty, tap, catchError, ignoreElements, finalize, takeUntil, skip, debounceTime, startWith } from 'rxjs/operators';
25
25
  import * as i1 from '@praxisui/core';
26
- import { serializeEntityLookupValueForPayload, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, providePraxisI18nConfig, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, migrateFormLayoutRule, PraxisJsonLogicService, normalizeFormLayoutItems, deepMerge, createDefaultFormConfig, normalizeFormConfig as normalizeFormConfig$1, ensureIds, createEmptyRichContentDocument, resolveHidden, resolveOrder, resolveSpan, projectGroupedCommandPartialRows, isPraxisRuntimeGlobalActionEffect, ASYNC_CONFIG_STORAGE, withFormConfigSections, createFieldLayoutItem, getFormLayoutFieldNames, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, ResourceDiscoveryService, GlobalActionService, SCHEMA_METADATA_CLIENT_OPTIONS, ResourceQuickConnectComponent, composeHeadersWithVersion, buildApiUrl, mapFieldDefinitionsToMetadata, reconcileFormConfig, applyLocalFormCustomizations, materializeFormLayoutFromMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, evaluateFieldAccess, normalizeControlTypeKey, normalizePraxisEffectPolicy, buildPraxisEffectDistinctKey, getFormColumnFieldNames, resolveGroupedCommandPartialRowSpans, resolveOffset, buildSchemaIdStorageKeySegment, buildSchemaId, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, DEFAULT_SCHEMA_REQUEST_TIMEOUT_MS, normalizeReactiveDeterminations, CONNECTION_STORAGE, API_URL, PRAXIS_LOADING_RENDERER, FORM_HOOKS_PRESETS, EmptyStateCardComponent, isValidFormConfig, ComponentMetadataRegistry, FieldControlType, isRequiredGlobalActionPayloadMissing, GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, getRequiredGlobalActionPayloadKeys, hasMeaningfulGlobalActionPayloadValue, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, IconPickerService, validateGlobalActionRefs, normalizeFormMetadata, projectComponentAuthoringManifest } from '@praxisui/core';
26
+ import { serializeEntityLookupValueForPayload, PraxisI18nService, PraxisIconButtonComponent, PraxisIconDirective, providePraxisI18nConfig, RULE_PROPERTY_SCHEMA, FIELD_METADATA_CAPABILITIES, migrateFormLayoutRule, PraxisJsonLogicService, normalizeFormLayoutItems, deepMerge, createDefaultFormConfig, normalizeFormConfig as normalizeFormConfig$1, ensureIds, createEmptyRichContentDocument, formIdentityIssues, resolveHidden, resolveOrder, resolveSpan, projectGroupedCommandPartialRows, isPraxisRuntimeGlobalActionEffect, ASYNC_CONFIG_STORAGE, withFormConfigSections, createFieldLayoutItem, getFormLayoutFieldNames, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, ResourceDiscoveryService, GlobalActionService, SCHEMA_METADATA_CLIENT_OPTIONS, ResourceQuickConnectComponent, composeHeadersWithVersion, buildApiUrl, readStrongResourceEtag, ApiEndpoint, mapFieldDefinitionsToMetadata, reconcileFormConfig, applyLocalFormCustomizations, materializeFormLayoutFromMetadata, syncWithServerMetadata, PRAXIS_LOADING_CTX, evaluateFieldAccess, normalizeControlTypeKey, normalizePraxisEffectPolicy, buildPraxisEffectDistinctKey, getFormColumnFieldNames, resolveGroupedCommandPartialRowSpans, resolveOffset, buildSchemaIdStorageKeySegment, buildSchemaId, fetchWithETag, resolveControlTypeAlias, getTextTransformer, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, DEFAULT_SCHEMA_REQUEST_TIMEOUT_MS, normalizeReactiveDeterminations, CONNECTION_STORAGE, API_URL, PRAXIS_LOADING_RENDERER, FORM_HOOKS_PRESETS, EmptyStateCardComponent, isValidFormConfig, ComponentMetadataRegistry, FieldControlType, isRequiredGlobalActionPayloadMissing, GLOBAL_ACTION_CATALOG, PRAXIS_GLOBAL_ACTION_CATALOG, getGlobalActionCatalog, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, getRequiredGlobalActionPayloadKeys, hasMeaningfulGlobalActionPayloadValue, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, IconPickerService, validateGlobalActionRefs, normalizeFormMetadata, DynamicFormService, projectComponentAuthoringManifest } from '@praxisui/core';
27
27
  import * as i1$1 from '@praxisui/dynamic-fields';
28
- import { getControlTypeCatalog, ConfirmDialogComponent, DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
28
+ import { getControlTypeCatalog, SelectOptionRegistry, ConfirmDialogComponent, DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
29
29
  import { BaseAiAdapter, AgenticAuthoringTurnClientService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnOrchestratorService, createPraxisAssistantViewportLayout, PraxisAiAssistantShellComponent } from '@praxisui/ai';
30
30
  import { PraxisRichContent, PraxisRichContentConfigEditor } from '@praxisui/rich-content';
31
31
  import * as i6 from '@angular/material/menu';
@@ -114,6 +114,7 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
114
114
  'actions.invalidRequired': 'Preencha os campos obrigatórios para continuar.',
115
115
  'actions.invalidRequiredWithFields': 'Preencha: {{fields}}.',
116
116
  'actions.submitErrorTitle': 'Erro ao salvar',
117
+ 'runtime.resourceVersion.reload': 'Recarregue os dados antes de salvar novamente.',
117
118
  'runtime.reactiveDetermination.error': 'Não foi possível atualizar os campos relacionados. Revise os dados ou tente novamente.',
118
119
  'runtime.reactiveDetermination.submitPending': 'Aguarde a atualização dos campos relacionados antes de salvar.',
119
120
  'runtime.reactiveDetermination.submitTimeout': 'Os campos relacionados não estabilizaram a tempo. Revise os dados e tente salvar novamente.',
@@ -704,6 +705,7 @@ const PRAXIS_DYNAMIC_FORM_I18N_CONFIG = {
704
705
  'actions.invalidRequired': 'Complete the required fields to continue.',
705
706
  'actions.invalidRequiredWithFields': 'Complete: {{fields}}.',
706
707
  'actions.submitErrorTitle': 'Save error',
708
+ 'runtime.resourceVersion.reload': 'Reload the data before saving again.',
707
709
  'config.tabs.mobileLabel': 'Editor section',
708
710
  'config.tabs.general': 'General',
709
711
  'config.tabs.schema': 'Schema Verification',
@@ -8932,7 +8934,11 @@ function validateDynamicFormAuthoringInput(raw, context) {
8932
8934
  const diagnostics = [];
8933
8935
  const obj = asRecord(raw);
8934
8936
  const rawConfig = asRecord(obj.config);
8935
- const layoutConfig = Object.prototype.hasOwnProperty.call(obj, 'config') ? rawConfig : obj;
8937
+ const layoutConfig = Object.prototype.hasOwnProperty.call(obj, 'config') ? rawConfig
8938
+ : Object.prototype.hasOwnProperty.call(obj, 'formConfig') ? asRecord(obj.formConfig) : obj;
8939
+ for (const issue of formIdentityIssues(layoutConfig)) {
8940
+ diagnostics.push({ ...issue, code: `dynamicForm.config.identity.${issue.code}`, path: `config.${issue.path}` });
8941
+ }
8936
8942
  if (Array.isArray(layoutConfig.sections)) {
8937
8943
  layoutConfig.sections.forEach((section, si) => {
8938
8944
  const rows = asRecord(section).rows;
@@ -9033,6 +9039,11 @@ function validateDynamicFormAuthoringInput(raw, context) {
9033
9039
  diagnostics.push(errorDiagnostic(`dynamicForm.contextSnapshot.presentation.${key}.invalid`, `presentation.${key} must be a non-negative number or null`, `contextSnapshot.presentation.${key}`));
9034
9040
  }
9035
9041
  });
9042
+ // An invalid sections collection cannot enter ensureIds normalization.
9043
+ // Keep other original diagnostics and normalized warnings on their existing path.
9044
+ if (diagnostics.some((diagnostic) => diagnostic.code === 'dynamicForm.config.sections.invalid')) {
9045
+ return dedupeDiagnostics(diagnostics);
9046
+ }
9036
9047
  const normalized = normalizeDynamicFormAuthoringDocument(parseLegacyOrDynamicFormDocument(raw));
9037
9048
  validateNormalizedDynamicFormAuthoringDocument(normalized, diagnostics, context);
9038
9049
  return dedupeDiagnostics(diagnostics);
@@ -11433,6 +11444,8 @@ class PraxisDynamicFormDestroyedError extends Error {
11433
11444
  this.name = 'PraxisDynamicFormDestroyedError';
11434
11445
  }
11435
11446
  }
11447
+ class PraxisDynamicFormResourceRevisionReloadError extends Error {
11448
+ }
11436
11449
  const FORM_CONFIG_LOAD_TIMEOUT_MS = 1200;
11437
11450
  const FORM_INPUT_PREFS_LOAD_TIMEOUT_MS = 1200;
11438
11451
  const SCHEMA_GLOBAL_CONFIG_READY_TIMEOUT_MS = 1200;
@@ -11491,6 +11504,7 @@ class PraxisDynamicForm {
11491
11504
  }
11492
11505
  }, ...(ngDevMode ? [{ debugName: "aiAssistantSessionEffect" }] : /* istanbul ignore next */ []));
11493
11506
  globalActions = inject(GlobalActionService, { optional: true });
11507
+ optionRegistry = inject(SelectOptionRegistry, { optional: true });
11494
11508
  DEBUG = typeof window !== 'undefined' &&
11495
11509
  Boolean(window['__PRAXIS_DEBUG__']);
11496
11510
  effectiveActionsCache;
@@ -11580,6 +11594,16 @@ class PraxisDynamicForm {
11580
11594
  configPersistenceStrategy = 'local-first';
11581
11595
  /** Optional layout to use instead of generated one */
11582
11596
  layout;
11597
+ /**
11598
+ * Layout mode for organizing form sections: 'vertical' (default), 'tabs' or 'accordion'.
11599
+ * Overrides config.layout.mode when specified.
11600
+ */
11601
+ layoutMode;
11602
+ /**
11603
+ * Layout configuration options for form sections (mode, tabs, defaultTabId, tabsAppearance, accordionMulti, etc.).
11604
+ * Merged with and takes precedence over config.layout.
11605
+ */
11606
+ formLayout;
11583
11607
  /** Metadata-driven layout preset used only when creating an initial config from schema. */
11584
11608
  generatedLayoutPreset = 'default';
11585
11609
  /** Opt-in policy for schema-driven transient layout materialization. */
@@ -11606,17 +11630,105 @@ class PraxisDynamicForm {
11606
11630
  presentationModeGlobal = null;
11607
11631
  /** Projection of contextSnapshot.presentation; null clears authored style overrides. */
11608
11632
  presentation;
11633
+ /**
11634
+ * Optional presentation preset applied when the form is rendered in presentation mode.
11635
+ * Resolves styles for standard patterns: 'corporate-dossier', 'editorial-card', 'compact-presentation' or 'default'.
11636
+ */
11637
+ presentationPreset;
11638
+ /**
11639
+ * Default visual appearance preset for sections when not explicitly configured at section level.
11640
+ * Values: 'card' (default), 'plain' (borderless with divider support), 'step' (stepper badge layout).
11641
+ */
11642
+ sectionDefaultAppearance;
11643
+ /**
11644
+ * Global flag to control divider lines between plain/dossier sections.
11645
+ * When true, renders a subtle separator line below each section (except the last).
11646
+ */
11647
+ sectionDivider;
11609
11648
  visibleGlobal = null;
11610
11649
  fieldIconPolicy = 'all';
11611
11650
  /** Opt-in loader for shared domain rule materializations persisted outside FormConfig. */
11612
11651
  domainRules = null;
11613
11652
  // Derived UI flags (single source of truth for template bindings)
11614
- // Policy: presentation is only effective when mode === 'view'.
11615
- // Hosts may keep presentationModeGlobal=true; in edit/create modes we ignore it.
11653
+ // Policy: presentation is effective when mode is explicitly 'presentation' / 'dossier' (Issue #36),
11654
+ // or when mode === 'view' and presentationModeGlobal is enabled or requested by layout policy.
11616
11655
  get effectivePresentation() {
11656
+ if (this.mode === 'presentation' || this.mode === 'dossier') {
11657
+ return true;
11658
+ }
11617
11659
  return (this.mode === 'view' &&
11618
11660
  (this.presentationModeGlobal === true || this.layoutPolicyRequestsPresentation()));
11619
11661
  }
11662
+ /** Normalizes presentation preset aliases and casing to canonical values. */
11663
+ normalizePresentationPreset(preset) {
11664
+ const raw = String(preset || '').trim();
11665
+ if (!raw)
11666
+ return 'default';
11667
+ if (raw === 'corporate-dossier' || raw === 'corporateDossier') {
11668
+ return 'corporate-dossier';
11669
+ }
11670
+ if (raw === 'editorial-card' || raw === 'editorialCard') {
11671
+ return 'editorial-card';
11672
+ }
11673
+ if (raw === 'compact-presentation' || raw === 'compactPresentation') {
11674
+ return 'compact-presentation';
11675
+ }
11676
+ return 'default';
11677
+ }
11678
+ /** Resolved presentation preset for the form container. */
11679
+ get effectivePresentationPreset() {
11680
+ if (!this.effectivePresentation) {
11681
+ return 'default';
11682
+ }
11683
+ if (this.presentationPreset) {
11684
+ return this.normalizePresentationPreset(this.presentationPreset);
11685
+ }
11686
+ const presInput = this.presentation?.presentationPreset ?? this.presentation?.preset;
11687
+ if (presInput) {
11688
+ return this.normalizePresentationPreset(presInput);
11689
+ }
11690
+ const configPres = this.config?.presentation?.presentationPreset ?? this.config?.presentation?.preset;
11691
+ if (configPres) {
11692
+ return this.normalizePresentationPreset(configPres);
11693
+ }
11694
+ const metaPres = this.config?.metadata?.presentationPreset;
11695
+ if (metaPres) {
11696
+ return this.normalizePresentationPreset(metaPres);
11697
+ }
11698
+ if (this.mode === 'dossier') {
11699
+ return 'corporate-dossier';
11700
+ }
11701
+ return 'default';
11702
+ }
11703
+ /** Resolved presentation preset for a specific section, allowing section-level override. */
11704
+ getSectionPresentationPreset(section) {
11705
+ if (!this.effectivePresentation) {
11706
+ return 'default';
11707
+ }
11708
+ const sectionPreset = section?.presentationPreset;
11709
+ if (sectionPreset) {
11710
+ return this.normalizePresentationPreset(sectionPreset);
11711
+ }
11712
+ return this.effectivePresentationPreset;
11713
+ }
11714
+ isCorporateDossierPreset() {
11715
+ return this.effectivePresentationPreset === 'corporate-dossier';
11716
+ }
11717
+ isEditorialCardPreset() {
11718
+ return this.effectivePresentationPreset === 'editorial-card';
11719
+ }
11720
+ isCompactPresentationPreset() {
11721
+ return this.effectivePresentationPreset === 'compact-presentation';
11722
+ }
11723
+ isSectionCorporateDossier(section) {
11724
+ return this.getSectionPresentationPreset(section) === 'corporate-dossier';
11725
+ }
11726
+ isSectionEditorialCard(section) {
11727
+ return this.getSectionPresentationPreset(section) === 'editorial-card';
11728
+ }
11729
+ isSectionCompactPresentation(section) {
11730
+ return this.getSectionPresentationPreset(section) === 'compact-presentation';
11731
+ }
11620
11732
  shouldShowContextEmptyState() {
11621
11733
  if (!this.emptyState || this.mode !== 'view')
11622
11734
  return false;
@@ -11636,7 +11748,10 @@ class PraxisDynamicForm {
11636
11748
  return !!value && Object.keys(value).length > 0;
11637
11749
  }
11638
11750
  get effectiveReadonly() {
11639
- return this.mode === 'view' || this.readonlyModeGlobal === true;
11751
+ return (this.mode === 'view' ||
11752
+ this.mode === 'presentation' ||
11753
+ this.mode === 'dossier' ||
11754
+ this.readonlyModeGlobal === true);
11640
11755
  }
11641
11756
  get effectiveDisabledMode() {
11642
11757
  if (this.entityHydrationPending || this.entityReadFailed) {
@@ -11699,6 +11814,9 @@ class PraxisDynamicForm {
11699
11814
  }
11700
11815
  /** Value propagated to DynamicFieldLoader; null allows per-field metadata */
11701
11816
  get presentationForLoader() {
11817
+ if (this.mode === 'presentation' || this.mode === 'dossier') {
11818
+ return true;
11819
+ }
11702
11820
  if (this.mode !== 'view') {
11703
11821
  return false;
11704
11822
  }
@@ -11817,10 +11935,13 @@ class PraxisDynamicForm {
11817
11935
  return this._customEndpoints;
11818
11936
  }
11819
11937
  set customEndpoints(value) {
11820
- this._customEndpoints = value;
11821
- if (value && Object.keys(value).length > 0) {
11822
- this.crud.configureEndpoints(value);
11938
+ // This input is a replacement snapshot. CRUD's public configureEndpoints remains a merge API.
11939
+ const removed = {};
11940
+ for (const key of Object.keys(this._customEndpoints)) {
11941
+ removed[key] = undefined;
11823
11942
  }
11943
+ this._customEndpoints = value ?? {};
11944
+ this.crud.configureEndpoints({ ...removed, ...this._customEndpoints });
11824
11945
  }
11825
11946
  formSubmit = new EventEmitter();
11826
11947
  formCancel = new EventEmitter();
@@ -11846,11 +11967,20 @@ class PraxisDynamicForm {
11846
11967
  reactiveDeterminationExecuted = new EventEmitter();
11847
11968
  /** Emits only aggregate runtime state; no request or response payload is exposed. */
11848
11969
  reactiveDeterminationPendingChange = new EventEmitter();
11970
+ /** Emitted when active tab changes in 'tabs' layout mode. */
11971
+ tabChange = new EventEmitter();
11972
+ /** Emitted when a tab is selected in 'tabs' layout mode. */
11973
+ tabSelected = new EventEmitter();
11974
+ /** Active tab ID when effectiveLayoutMode === 'tabs'. */
11975
+ activeTabId = null;
11849
11976
  reactiveDeterminationPending = false;
11850
11977
  // Estado interno para UX
11851
11978
  isLoading = false;
11852
11979
  submitting = false;
11853
11980
  submitPreparationInProgress = false;
11981
+ submitLifecycleSequence = 0;
11982
+ activeSubmitLifecycle = null;
11983
+ activeSubmitAutomatic = false;
11854
11984
  submitError = null;
11855
11985
  initializationStatus = 'idle';
11856
11986
  currentErrorMessage = '';
@@ -11903,6 +12033,9 @@ class PraxisDynamicForm {
11903
12033
  entitySelectionCleared = false;
11904
12034
  hydratedEntityId = null;
11905
12035
  loadedEntityData = null;
12036
+ loadedResourceRevision = null;
12037
+ resourceRevisionInvalidated = false;
12038
+ entityReadAttempt = 0;
11906
12039
  entityHydrationPending = false;
11907
12040
  entityReadFailed = false;
11908
12041
  entityReadText(key) {
@@ -12430,16 +12563,25 @@ class PraxisDynamicForm {
12430
12563
  const method = this.normalizeSubmitMethod(this.submitMethod);
12431
12564
  const configuredSubmitUrl = String(this.submitUrl || '').trim();
12432
12565
  if (!method && !configuredSubmitUrl) {
12433
- return operation === 'update'
12434
- ? this.crud.update(this.resourceId, formData)
12435
- : this.crud.create(formData);
12566
+ if (operation !== 'update')
12567
+ return this.crud.create(formData);
12568
+ const binding = this.resourceRevisionBinding();
12569
+ const revisionEpoch = this.entityReadAttempt;
12570
+ if (this.resourceRevisionNeedsReload(binding))
12571
+ return this.resourceRevisionReloadError();
12572
+ const originalVersion = this.loadedResourceRevision?.etag ?? null;
12573
+ return this.crud.updateHttpResponse(this.resourceId, formData, { resourceVersion: originalVersion }).pipe(filter(() => this.isResourceRevisionCurrent(binding, revisionEpoch)), tap((response) => this.captureSavedResourceRevision(response, binding, originalVersion != null, revisionEpoch)), map$1((response) => this.unwrapRestApiResponse(response.body)), catchError((error) => this.isResourceRevisionCurrent(binding, revisionEpoch)
12574
+ ? this.rejectResourceRevision(error, binding, revisionEpoch) : EMPTY));
12436
12575
  }
12437
12576
  if (!method || !configuredSubmitUrl) {
12438
12577
  return throwError(() => new Error('PraxisDynamicForm requires submitMethod and submitUrl together for canonical submit execution.'));
12439
12578
  }
12440
12579
  const resolvedUrl = this.resolveSubmitHref(configuredSubmitUrl);
12580
+ const automaticItemRevision = this.usesAutomaticItemRevision();
12581
+ const binding = this.resourceRevisionBinding();
12582
+ const revisionEpoch = this.entityReadAttempt;
12441
12583
  return this.resolveSubmitResourceVersion(formData).pipe(switchMap((resolvedResourceVersion) => {
12442
- let headers = composeHeadersWithVersion(this.resolveApiEntry()) ?? new HttpHeaders();
12584
+ let headers = (composeHeadersWithVersion(this.resolveApiEntry()) ?? new HttpHeaders()).delete('If-Match');
12443
12585
  const idempotencyKey = String(this.submitIdempotencyKey || '').trim();
12444
12586
  if (idempotencyKey) {
12445
12587
  headers = headers.set('Idempotency-Key', idempotencyKey);
@@ -12451,30 +12593,32 @@ class PraxisDynamicForm {
12451
12593
  if (resolvedResourceVersion) {
12452
12594
  headers = headers.set('If-Match', this.formatResourceVersion(resolvedResourceVersion));
12453
12595
  }
12454
- if (method === 'patch') {
12455
- return this.http
12456
- .patch(resolvedUrl, formData, { headers })
12457
- .pipe(map$1((response) => this.unwrapRestApiResponse(response)));
12458
- }
12459
- if (method === 'put') {
12460
- return this.http
12461
- .put(resolvedUrl, formData, { headers })
12462
- .pipe(map$1((response) => this.unwrapRestApiResponse(response)));
12463
- }
12464
- return this.http
12465
- .post(resolvedUrl, formData, { headers })
12466
- .pipe(map$1((response) => this.unwrapRestApiResponse(response)));
12596
+ return this.http.request(method.toUpperCase(), resolvedUrl, {
12597
+ body: formData, headers, observe: 'response',
12598
+ }).pipe(filter(() => !automaticItemRevision || this.isResourceRevisionCurrent(binding, revisionEpoch)), tap((response) => {
12599
+ if (automaticItemRevision)
12600
+ this.captureSavedResourceRevision(response, binding, resolvedResourceVersion != null, revisionEpoch);
12601
+ }), map$1((response) => this.unwrapRestApiResponse(response.body)), catchError((error) => automaticItemRevision
12602
+ ? this.isResourceRevisionCurrent(binding, revisionEpoch)
12603
+ ? this.rejectResourceRevision(error, binding, revisionEpoch) : EMPTY
12604
+ : throwError(() => error)));
12467
12605
  }));
12468
12606
  }
12469
12607
  resolveSubmitResourceVersion(formData) {
12470
- const explicitVersion = String(this.submitResourceVersion ?? '').trim();
12608
+ const explicitVersion = this.normalizeResourceVersionToken(this.submitResourceVersion);
12471
12609
  if (explicitVersion) {
12472
12610
  return of(explicitVersion);
12473
12611
  }
12474
12612
  const targetResourceKey = String(this.submitResourceVersionTargetResourceKey ?? '').trim();
12475
12613
  const targetIdField = String(this.submitResourceVersionTargetIdField ?? '').trim();
12476
12614
  if (!targetResourceKey && !targetIdField) {
12477
- return of(null);
12615
+ const method = this.normalizeSubmitMethod(this.submitMethod);
12616
+ if (method !== 'put' && method !== 'patch')
12617
+ return of(null);
12618
+ const binding = this.resourceRevisionBinding();
12619
+ if (this.resourceRevisionNeedsReload(binding))
12620
+ return this.resourceRevisionReloadError();
12621
+ return of(this.loadedResourceRevision?.etag ?? null);
12478
12622
  }
12479
12623
  if (!targetResourceKey || !targetIdField) {
12480
12624
  return throwError(() => new Error('PraxisDynamicForm requires both submitResourceVersionTargetResourceKey and submitResourceVersionTargetIdField.'));
@@ -12515,12 +12659,119 @@ class PraxisDynamicForm {
12515
12659
  observe: 'response',
12516
12660
  });
12517
12661
  }), switchMap((response) => {
12518
- const etag = String(response.headers.get('ETag') || '').trim();
12662
+ const etag = this.normalizeResourceVersionToken(response.headers?.get?.('ETag')) ??
12663
+ this.extractResourceVersionCandidate(this.unwrapRestApiResponse(response.body));
12519
12664
  return etag
12520
12665
  ? of(etag)
12521
12666
  : throwError(() => new Error(`PraxisDynamicForm did not receive an ETag for cross-resource target "${targetResourceKey}".`));
12522
12667
  }));
12523
12668
  }
12669
+ /** Identity and server context are captured with the representation, never reconstructed at submit by GET. */
12670
+ resourceRevisionBinding() {
12671
+ const entry = this.resolveApiEntry();
12672
+ const headers = composeHeadersWithVersion(entry);
12673
+ const context = this.enterpriseRuntimeContext?.snapshot;
12674
+ return JSON.stringify({
12675
+ id: this.resourceId ?? this.pendingEntityId ?? null,
12676
+ resourcePath: this.resourcePath ?? null,
12677
+ readUrl: this.readUrl ?? null,
12678
+ customEndpoints: this.customEndpoints ?? null,
12679
+ submitUrl: this.submitUrl ?? null,
12680
+ submitMethod: this.normalizeSubmitMethod(this.submitMethod),
12681
+ origin: buildApiUrl(entry),
12682
+ headers: headers?.keys().sort().map((name) => [name, headers?.getAll(name)]),
12683
+ user: context?.user.userId ?? null,
12684
+ state: context?.state ?? null,
12685
+ selectionVersion: context?.selectionVersion ?? null,
12686
+ contextVersion: context?.effectiveContext?.contextVersion ?? null,
12687
+ organization: context?.effectiveContext?.activeOrganizationId ?? null,
12688
+ tenant: context?.effectiveContext?.activeTenant.tenantId ?? null,
12689
+ environment: context?.effectiveContext?.environment ?? null,
12690
+ profile: context?.effectiveContext?.activeProfileId ?? null,
12691
+ module: context?.effectiveContext?.activeModuleKey ?? null,
12692
+ });
12693
+ }
12694
+ usesAutomaticItemRevision() {
12695
+ return this.mode !== 'create' && this.resolveSubmitOperation() !== 'create'
12696
+ && !String(this.submitResourceVersion ?? '').trim()
12697
+ && !String(this.submitResourceVersionTargetResourceKey ?? '').trim()
12698
+ && !String(this.submitResourceVersionTargetIdField ?? '').trim();
12699
+ }
12700
+ isResourceRevisionCurrent(binding, epoch) {
12701
+ return !this.isDestroyed && epoch === this.entityReadAttempt && binding === this.resourceRevisionBinding();
12702
+ }
12703
+ invalidateAutomaticSubmitUi() {
12704
+ if (!this.activeSubmitAutomatic)
12705
+ return;
12706
+ this.activeSubmitLifecycle = null;
12707
+ this.activeSubmitAutomatic = false;
12708
+ this.submitting = false;
12709
+ this.submitPreparationInProgress = false;
12710
+ try {
12711
+ this._activeSnack?.dismiss();
12712
+ }
12713
+ catch { }
12714
+ this._activeSnack = null;
12715
+ }
12716
+ resourceRevisionNeedsReload(binding) {
12717
+ return this.resourceRevisionInvalidated
12718
+ || this.loadedResourceRevision != null && this.loadedResourceRevision.binding !== binding;
12719
+ }
12720
+ resourceRevisionReloadError() {
12721
+ return throwError(() => new PraxisDynamicFormResourceRevisionReloadError(this.i18n.t('runtime.resourceVersion.reload', undefined, 'Recarregue os dados antes de salvar novamente.', PRAXIS_DYNAMIC_FORM_I18N_NAMESPACE)));
12722
+ }
12723
+ captureSavedResourceRevision(response, binding, required, epoch) {
12724
+ if (epoch !== this.entityReadAttempt || binding !== this.resourceRevisionBinding())
12725
+ return;
12726
+ const data = this.unwrapRestApiResponse(response.body);
12727
+ const representsOriginal = data != null && typeof data === 'object' && !Array.isArray(data)
12728
+ && Object.keys(this.loadedEntityData ?? {}).every((key) => Object.prototype.hasOwnProperty.call(data, key))
12729
+ && (!Object.prototype.hasOwnProperty.call(data, 'id') || this.resourceId == null
12730
+ || String(data['id']) === String(this.resourceId));
12731
+ if (!representsOriginal) {
12732
+ // A command acknowledgment/partial response is not a new item representation.
12733
+ this.loadedResourceRevision = null;
12734
+ this.loadedEntityId = null;
12735
+ this.loadedEntityData = null;
12736
+ this.resourceRevisionInvalidated = required;
12737
+ return;
12738
+ }
12739
+ const normalized = this.normalizeFormPatchValue(data);
12740
+ this.loadedEntityData = normalized;
12741
+ this.loadedEntityId = this.resourceId ?? this.pendingEntityId;
12742
+ this.form.patchValue(normalized);
12743
+ const etag = readStrongResourceEtag(response.headers.get('ETag'));
12744
+ this.loadedResourceRevision = { binding, etag };
12745
+ this.resourceRevisionInvalidated = required && etag == null;
12746
+ }
12747
+ rejectResourceRevision(error, binding, epoch) {
12748
+ if (error instanceof HttpErrorResponse && (error.status === 412 || error.status === 428)
12749
+ && epoch === this.entityReadAttempt && binding === this.resourceRevisionBinding()) {
12750
+ this.loadedResourceRevision = null;
12751
+ this.resourceRevisionInvalidated = true;
12752
+ }
12753
+ return throwError(() => error);
12754
+ }
12755
+ normalizeResourceVersionToken(raw) {
12756
+ if (typeof raw !== 'string' && typeof raw !== 'number') {
12757
+ return null;
12758
+ }
12759
+ const trimmed = String(raw).trim();
12760
+ if (!trimmed) {
12761
+ return null;
12762
+ }
12763
+ const unquoted = trimmed
12764
+ .replace(/^W\//i, '')
12765
+ .replace(/^"|"$/g, '')
12766
+ .trim();
12767
+ return unquoted ? trimmed : null;
12768
+ }
12769
+ extractResourceVersionCandidate(source) {
12770
+ if (!source || typeof source !== 'object' || Array.isArray(source)) {
12771
+ return null;
12772
+ }
12773
+ return this.normalizeResourceVersionToken(source['resourceVersion']);
12774
+ }
12524
12775
  normalizeSubmitMethod(value) {
12525
12776
  const normalized = String(value || '')
12526
12777
  .trim()
@@ -12531,10 +12782,15 @@ class PraxisDynamicForm {
12531
12782
  return null;
12532
12783
  }
12533
12784
  formatResourceVersion(version) {
12534
- if (/^(?:W\/)?".*"$/.test(version)) {
12535
- return version;
12785
+ const trimmed = version.trim();
12786
+ if (/^(?:W\/)?"[^"]+"$/.test(trimmed)) {
12787
+ return trimmed;
12536
12788
  }
12537
- return `"${version.replace(/^"|"$/g, '')}"`;
12789
+ const unquoted = trimmed
12790
+ .replace(/^W\//i, '')
12791
+ .replace(/^"|"$/g, '')
12792
+ .trim();
12793
+ return `"${unquoted}"`;
12538
12794
  }
12539
12795
  resolveSubmitHref(submitUrl) {
12540
12796
  return this.resolveEntityAwareHref(submitUrl, 'PraxisDynamicForm cannot resolve submitUrl placeholders without a resourceId.');
@@ -12603,7 +12859,7 @@ class PraxisDynamicForm {
12603
12859
  return;
12604
12860
  }
12605
12861
  this.crud.configure(this.resourcePath, {
12606
- endpointKey: this.apiEndpointKey ?? undefined,
12862
+ endpointKey: this.apiEndpointKey || ApiEndpoint.Default,
12607
12863
  apiUrlEntry: this.apiUrlEntry ?? null,
12608
12864
  });
12609
12865
  }
@@ -12682,7 +12938,11 @@ class PraxisDynamicForm {
12682
12938
  Math.random().toString(36).slice(2, 11));
12683
12939
  }
12684
12940
  resolveModeKey(value) {
12685
- if (value === 'edit' || value === 'view' || value === 'create')
12941
+ if (value === 'edit' ||
12942
+ value === 'view' ||
12943
+ value === 'create' ||
12944
+ value === 'presentation' ||
12945
+ value === 'dossier')
12686
12946
  return value;
12687
12947
  return 'create';
12688
12948
  }
@@ -12771,22 +13031,35 @@ class PraxisDynamicForm {
12771
13031
  this.cdr.detectChanges();
12772
13032
  }
12773
13033
  reloadForModeChange() {
12774
- if (!this.inputsLoaded || !this.formId || !this.hasSchemaBackedRuntime())
13034
+ if (!this.inputsLoaded || !this.formId || !this.hasSchemaBackedRuntime()) {
13035
+ this.cdr.markForCheck();
12775
13036
  return;
13037
+ }
12776
13038
  this.retryInitialization();
12777
13039
  }
12778
- ngOnInit() {
12779
- this.debugLog('[PDF] ngOnInit gating', {
12780
- formId: this.formId,
12781
- resourcePath: this.resourcePath,
12782
- });
12783
- this.inputsLoaded = !this.formId;
12784
- if (!this.formId && !this.resourcePath && this.hasRenderableConfig()) {
12785
- this.initializeStandaloneConfig();
12786
- }
13040
+ resourceRevisionContextScope() {
13041
+ const context = this.enterpriseRuntimeContext?.snapshot;
13042
+ return JSON.stringify([context?.state, context?.selectionVersion, context?.effectiveContext?.contextVersion,
13043
+ context?.effectiveContext?.activeOrganizationId, context?.user.userId, context?.effectiveContext?.activeTenant.tenantId,
13044
+ context?.effectiveContext?.environment, context?.effectiveContext?.activeProfileId, context?.effectiveContext?.activeModuleKey]);
13045
+ }
13046
+ subscribeToRuntimeContextChanges() {
13047
+ let lastScope = this.resourceRevisionContextScope();
12787
13048
  this.enterpriseRuntimeContext?.contextChanges$
12788
13049
  .pipe(takeUntil(this.destroy$), skip(1))
12789
13050
  .subscribe(() => {
13051
+ const scope = this.resourceRevisionContextScope();
13052
+ if (scope !== lastScope) {
13053
+ lastScope = scope;
13054
+ this.invalidateAutomaticSubmitUi();
13055
+ this.entityReadAttempt++;
13056
+ this.loadedResourceRevision = null;
13057
+ this.resourceRevisionInvalidated = this.mode !== 'create';
13058
+ this.loadedEntityId = null;
13059
+ this.loadedEntityData = null;
13060
+ this.hydratedEntityId = null;
13061
+ this.entityHydrationPending = false;
13062
+ }
12790
13063
  this.runtimeFieldMetadata = null;
12791
13064
  if (this.hasBuiltFormFromConfig && this.hasRenderableConfig()) {
12792
13065
  this.buildFormFromConfig({
@@ -12798,6 +13071,18 @@ class PraxisDynamicForm {
12798
13071
  this.cdr.markForCheck();
12799
13072
  }
12800
13073
  });
13074
+ }
13075
+ ngOnInit() {
13076
+ this.debugLog('[PDF] ngOnInit gating', {
13077
+ formId: this.formId,
13078
+ resourcePath: this.resourcePath,
13079
+ });
13080
+ this.inputsLoaded = !this.formId;
13081
+ if (!this.formId && !this.resourcePath && this.hasRenderableConfig()) {
13082
+ this.initializeStandaloneConfig();
13083
+ }
13084
+ this.ensureActiveTabValid();
13085
+ this.subscribeToRuntimeContextChanges();
12801
13086
  // Load persisted connection if not provided via input
12802
13087
  const connKey = this.connectionKey();
12803
13088
  if (!this.resourcePath && connKey) {
@@ -12913,9 +13198,23 @@ class PraxisDynamicForm {
12913
13198
  }
12914
13199
  }
12915
13200
  ngOnChanges(changes) {
13201
+ const revisionIdentityChanged = ['resourceId', 'resourcePath', 'readUrl', 'customEndpoints',
13202
+ 'apiEndpointKey', 'apiUrlEntry', 'submitUrl', 'submitMethod', 'mode']
13203
+ .some((key) => changes[key] && !changes[key].firstChange);
13204
+ if (revisionIdentityChanged) {
13205
+ this.invalidateAutomaticSubmitUi();
13206
+ this.entityReadAttempt++;
13207
+ this.loadedResourceRevision = null;
13208
+ this.resourceRevisionInvalidated = this.mode !== 'create';
13209
+ this.loadedEntityId = null;
13210
+ this.loadedEntityData = null;
13211
+ this.hydratedEntityId = null;
13212
+ }
12916
13213
  // Assert invalid combos: presentationModeGlobal=true is only effective in view mode
12917
13214
  if ((changes['mode'] || changes['presentationModeGlobal']) &&
12918
13215
  this.mode !== 'view' &&
13216
+ this.mode !== 'presentation' &&
13217
+ this.mode !== 'dossier' &&
12919
13218
  this.presentationModeGlobal === true) {
12920
13219
  try {
12921
13220
  this.warnLog('[PraxisDynamicForm] presentationModeGlobal=true is ignored when mode != "view". Rendering in input mode.', { mode: this.mode });
@@ -12928,12 +13227,12 @@ class PraxisDynamicForm {
12928
13227
  this.canvasState.setSelectedElement(null);
12929
13228
  this.cdr.detectChanges();
12930
13229
  }
12931
- if (changes['resourcePath'] && this.resourcePath) {
13230
+ if ((changes['resourcePath'] || changes['apiEndpointKey'] || changes['apiUrlEntry'] || changes['customEndpoints']) && this.resourcePath) {
12932
13231
  this.debugLog('[PDF] ngOnChanges resourcePath=', this.resourcePath, ' -> configure()');
12933
13232
  this.saveConnection('input');
12934
13233
  this.configureCrudRuntime();
12935
13234
  // A new resource supersedes schema work for the previous resource.
12936
- if (!changes['resourcePath'].firstChange && this.formId) {
13235
+ if (changes['resourcePath'] && !changes['resourcePath'].firstChange && this.formId) {
12937
13236
  this.retryInitialization();
12938
13237
  }
12939
13238
  else if (!this.isInitialized && !this.isLoading && this.formId) {
@@ -12948,6 +13247,7 @@ class PraxisDynamicForm {
12948
13247
  }
12949
13248
  if (changes['mode'] && !changes['mode'].firstChange) {
12950
13249
  this.reloadForModeChange();
13250
+ this.cdr.markForCheck();
12951
13251
  }
12952
13252
  if (changes['resourceId']) {
12953
13253
  this.debugLog('[PDF] ngOnChanges resourceId=', this.resourceId);
@@ -12989,6 +13289,7 @@ class PraxisDynamicForm {
12989
13289
  this.form.markAsPristine();
12990
13290
  this.form.markAsUntouched();
12991
13291
  this.loadedEntityData = normalized;
13292
+ this.loadedResourceRevision = null;
12992
13293
  this.hydratedEntityId = this.pendingEntityId;
12993
13294
  this.flushEntityHydrationState();
12994
13295
  this.emitPayloadPreview('entity-hydrated');
@@ -13010,6 +13311,10 @@ class PraxisDynamicForm {
13010
13311
  this.loadEntity();
13011
13312
  }
13012
13313
  }
13314
+ if (revisionIdentityChanged && this.config.fieldMetadata?.length && this.pendingEntityId != null
13315
+ && !changes['resourceId'] && !changes['mode'] && !changes['readUrl']) {
13316
+ this.loadEntity();
13317
+ }
13013
13318
  if (changes['config'] || changes['presentationModeGlobal'] || changes['domainRules']) {
13014
13319
  let shouldRebuildFromExternalConfig = false;
13015
13320
  let externalConfigChanged = false;
@@ -13057,9 +13362,15 @@ class PraxisDynamicForm {
13057
13362
  this.verifyServerSchemaVersion().catch(() => { });
13058
13363
  }
13059
13364
  }
13060
- if (changes['presentation']) {
13365
+ if (changes['presentation'] || changes['presentationPreset']) {
13061
13366
  this.resetPresentationVarsToDefaults();
13062
13367
  this.applyPresentationVars();
13368
+ this.sectionClassesCache.clear();
13369
+ this.cdr.markForCheck();
13370
+ }
13371
+ if (changes['formLayout'] || changes['layoutMode'] || changes['config']) {
13372
+ this.ensureActiveTabValid();
13373
+ this.cdr.markForCheck();
13063
13374
  }
13064
13375
  // Update resolved schema prefs when related @Inputs change
13065
13376
  if (changes['notifyIfOutdated'] || changes['snoozeMs'] || changes['autoOpenSettingsOnOutdated']) {
@@ -13600,7 +13911,8 @@ class PraxisDynamicForm {
13600
13911
  return;
13601
13912
  }
13602
13913
  // Avoid duplicate network requests but allow re-patching after form build
13603
- if (this.loadedEntityId === this.pendingEntityId) {
13914
+ if (this.loadedEntityId === this.pendingEntityId && !this.resourceRevisionInvalidated
13915
+ && (this.loadedResourceRevision == null || this.loadedResourceRevision.binding === this.resourceRevisionBinding())) {
13604
13916
  if (this.loadedEntityData && Object.keys(this.form.controls).length) {
13605
13917
  this.entityHydrationPending = false;
13606
13918
  this.form.patchValue(this.normalizeFormPatchValue(this.loadedEntityData));
@@ -13631,6 +13943,10 @@ class PraxisDynamicForm {
13631
13943
  this.entityReadCancel$.next();
13632
13944
  this.loadedEntityData = null;
13633
13945
  this.loadedEntityId = this.pendingEntityId;
13946
+ const binding = this.resourceRevisionBinding();
13947
+ const attempt = ++this.entityReadAttempt;
13948
+ this.loadedResourceRevision = null;
13949
+ this.resourceRevisionInvalidated = true;
13634
13950
  this.entityHydrationPending = true;
13635
13951
  this.entityReadFailed = false;
13636
13952
  this.flushEntityHydrationState();
@@ -13641,15 +13957,20 @@ class PraxisDynamicForm {
13641
13957
  .get(this.resolveReadHref(configuredReadUrl), {
13642
13958
  context: httpContext,
13643
13959
  headers: composeHeadersWithVersion(this.resolveApiEntry()),
13960
+ observe: 'response',
13644
13961
  })
13645
- .pipe(map$1((response) => this.unwrapRestApiResponse(response)))
13646
- : this.crud.getById(this.pendingEntityId, { httpContext });
13962
+ : this.crud.getByIdHttpResponse(this.pendingEntityId, { httpContext });
13647
13963
  request$
13648
13964
  .pipe(takeUntil(this.entityReadCancel$), takeUntil(this.destroy$))
13649
13965
  .subscribe({
13650
- next: (data) => {
13966
+ next: (response) => {
13967
+ if (attempt !== this.entityReadAttempt || binding !== this.resourceRevisionBinding())
13968
+ return;
13969
+ const data = this.unwrapRestApiResponse(response.body);
13651
13970
  this.entityHydrationPending = false;
13652
13971
  if (data && typeof data === 'object' && !Array.isArray(data)) {
13972
+ this.loadedResourceRevision = { binding, etag: readStrongResourceEtag(response.headers.get('ETag')) };
13973
+ this.resourceRevisionInvalidated = false;
13653
13974
  const normalized = this.normalizeFormPatchValue(data);
13654
13975
  this.loadedEntityData = normalized;
13655
13976
  if (Object.keys(this.form.controls).length) {
@@ -13668,15 +13989,21 @@ class PraxisDynamicForm {
13668
13989
  else {
13669
13990
  this.entityReadFailed = true;
13670
13991
  this.loadedEntityId = null;
13992
+ this.loadedResourceRevision = null;
13993
+ this.resourceRevisionInvalidated = true;
13671
13994
  this.warnLog('Invalid entity data received:', data, { actionId: 'entity.load', throttleKey: 'praxis-dynamic-form:invalid-entity-data' });
13672
13995
  this.emitLoadingState('data', 'error', 'Dados inválidos recebidos.');
13673
13996
  this.flushEntityHydrationState();
13674
13997
  }
13675
13998
  },
13676
13999
  error: (err) => {
14000
+ if (attempt !== this.entityReadAttempt || binding !== this.resourceRevisionBinding())
14001
+ return;
13677
14002
  this.entityHydrationPending = false;
13678
14003
  this.entityReadFailed = true;
13679
14004
  this.loadedEntityId = null;
14005
+ this.loadedResourceRevision = null;
14006
+ this.resourceRevisionInvalidated = true;
13680
14007
  this.flushEntityHydrationState();
13681
14008
  this.emitLoadingState('data', 'error', 'Erro ao carregar dados.', err);
13682
14009
  },
@@ -13687,6 +14014,8 @@ class PraxisDynamicForm {
13687
14014
  if (!normalized) {
13688
14015
  return false;
13689
14016
  }
14017
+ // An externally supplied DTO is not a paired HTTP read revision.
14018
+ this.loadedResourceRevision = null;
13690
14019
  this.loadedEntityId = this.pendingEntityId;
13691
14020
  this.loadedEntityData = normalized;
13692
14021
  this.entityHydrationPending = false;
@@ -13825,6 +14154,8 @@ class PraxisDynamicForm {
13825
14154
  }
13826
14155
  scheduleReactiveDeterminationsActivation(buildCycleId) {
13827
14156
  if (this.mode === 'view' ||
14157
+ this.mode === 'presentation' ||
14158
+ this.mode === 'dossier' ||
13828
14159
  !this.schemaRootReactiveDeterminations.length ||
13829
14160
  !this.form ||
13830
14161
  buildCycleId !== this.formBuildCycleId ||
@@ -13836,6 +14167,8 @@ class PraxisDynamicForm {
13836
14167
  queueMicrotask(() => {
13837
14168
  if (buildCycleId !== this.formBuildCycleId ||
13838
14169
  this.mode === 'view' ||
14170
+ this.mode === 'presentation' ||
14171
+ this.mode === 'dossier' ||
13839
14172
  (this.pendingEntityId != null && this.hydratedEntityId !== this.pendingEntityId)) {
13840
14173
  if (this.reactiveDeterminationScheduledBuildId === buildCycleId) {
13841
14174
  this.reactiveDeterminationScheduledBuildId = 0;
@@ -13847,7 +14180,7 @@ class PraxisDynamicForm {
13847
14180
  connection.add(this.reactiveDeterminationRuntime.connect(this.form, this.schemaRootReactiveDeterminations.filter((definition) => definition.scope.formMode === this.mode
13848
14181
  && (!this.schemaRootOperationId
13849
14182
  || definition.scope.schemaOperationId === this.schemaRootOperationId)), (definition, requestBody, correlationId) => {
13850
- let headers = composeHeadersWithVersion(this.resolveApiEntry()) ?? new HttpHeaders();
14183
+ let headers = (composeHeadersWithVersion(this.resolveApiEntry()) ?? new HttpHeaders()).delete('If-Match');
13851
14184
  headers = headers.set('X-Correlation-Id', correlationId);
13852
14185
  return this.http
13853
14186
  .post(resolveReactiveDeterminationHref(definition.capability.href, this.resolveApiOrigin()), requestBody, { headers })
@@ -14016,7 +14349,7 @@ class PraxisDynamicForm {
14016
14349
  if (configuredAuthorities) {
14017
14350
  return configuredAuthorities;
14018
14351
  }
14019
- return this.normalizeAuthorityClaims(this.enterpriseRuntimeContext?.snapshot?.authorities);
14352
+ return this.normalizeAuthorityClaims(this.enterpriseRuntimeContext?.effectiveContext?.authorities);
14020
14353
  }
14021
14354
  normalizeAuthorityClaims(value) {
14022
14355
  if (!Array.isArray(value)) {
@@ -14893,16 +15226,150 @@ class PraxisDynamicForm {
14893
15226
  this.ruleApplicationDiagnostics = next;
14894
15227
  this.ruleDiagnosticsChange.emit(next);
14895
15228
  }
15229
+ get effectiveLayoutMode() {
15230
+ return this.layoutMode || this.formLayout?.mode || this.config?.layout?.mode || 'vertical';
15231
+ }
15232
+ get effectiveTabsAppearance() {
15233
+ return this.formLayout?.tabsAppearance || this.config?.layout?.tabsAppearance || 'pills';
15234
+ }
15235
+ get effectiveAccordionMulti() {
15236
+ return this.formLayout?.accordionMulti ?? this.config?.layout?.accordionMulti ?? false;
15237
+ }
15238
+ get effectiveHideSectionHeaderInTabs() {
15239
+ return this.formLayout?.hideSectionHeaderInTabs ?? this.config?.layout?.hideSectionHeaderInTabs ?? false;
15240
+ }
15241
+ get effectiveTabs() {
15242
+ const configuredTabs = (this.formLayout?.tabs?.length ?? 0) > 0
15243
+ ? this.formLayout.tabs
15244
+ : (this.config?.layout?.tabs?.length ?? 0) > 0
15245
+ ? this.config.layout.tabs
15246
+ : null;
15247
+ if (configuredTabs && configuredTabs.length > 0) {
15248
+ return configuredTabs;
15249
+ }
15250
+ // Auto-derive 1 tab per visible section
15251
+ const sections = (this.config?.sections || []).filter((s) => this.isSectionVisible(s));
15252
+ return sections.map((section, idx) => ({
15253
+ id: section.id || `section-tab-${idx}`,
15254
+ label: this.getSectionTitle(section) || section.id || `Seção ${idx + 1}`,
15255
+ icon: section.icon || section.sectionHeader?.fallbackIcon,
15256
+ sectionIds: [section.id],
15257
+ }));
15258
+ }
15259
+ ensureActiveTabValid() {
15260
+ if (this.effectiveLayoutMode !== 'tabs') {
15261
+ return;
15262
+ }
15263
+ const tabs = this.effectiveTabs;
15264
+ if (!tabs || tabs.length === 0) {
15265
+ this.activeTabId = null;
15266
+ return;
15267
+ }
15268
+ if (!this.activeTabId || !tabs.some((t) => t.id === this.activeTabId)) {
15269
+ const defaultId = this.formLayout?.defaultTabId || this.config?.layout?.defaultTabId;
15270
+ if (defaultId && tabs.some((t) => t.id === defaultId && !t.disabled)) {
15271
+ this.activeTabId = defaultId;
15272
+ }
15273
+ else {
15274
+ const firstEnabled = tabs.find((t) => !t.disabled) || tabs[0];
15275
+ this.activeTabId = firstEnabled ? firstEnabled.id : null;
15276
+ }
15277
+ }
15278
+ }
15279
+ selectTab(tabId) {
15280
+ const tab = this.effectiveTabs.find((t) => t.id === tabId);
15281
+ if (!tab || tab.disabled) {
15282
+ return;
15283
+ }
15284
+ if (this.activeTabId !== tabId) {
15285
+ this.activeTabId = tabId;
15286
+ this.tabChange.emit(tabId);
15287
+ this.tabSelected.emit(tab);
15288
+ try {
15289
+ this.cdr.markForCheck();
15290
+ }
15291
+ catch { }
15292
+ }
15293
+ }
15294
+ isSectionInActiveTab(section) {
15295
+ if (this.effectiveLayoutMode !== 'tabs') {
15296
+ return true;
15297
+ }
15298
+ if (!section || !section.id) {
15299
+ return true;
15300
+ }
15301
+ const tabs = this.effectiveTabs;
15302
+ if (!tabs.length) {
15303
+ return true;
15304
+ }
15305
+ this.ensureActiveTabValid();
15306
+ const activeTab = tabs.find((t) => t.id === this.activeTabId);
15307
+ if (!activeTab) {
15308
+ return true;
15309
+ }
15310
+ return (activeTab.sectionIds || []).includes(section.id);
15311
+ }
15312
+ getTabErrorCount(tab) {
15313
+ if (!this.form || !tab.sectionIds?.length) {
15314
+ return 0;
15315
+ }
15316
+ let errorCount = 0;
15317
+ const allSections = this.config?.sections || [];
15318
+ for (const sectionId of tab.sectionIds) {
15319
+ const section = allSections.find((s) => s.id === sectionId);
15320
+ if (!section)
15321
+ continue;
15322
+ for (const row of section.rows || []) {
15323
+ for (const col of row.columns || []) {
15324
+ for (const fieldName of getFormColumnFieldNames(col)) {
15325
+ const ctrl = this.form.get(fieldName);
15326
+ if (ctrl && ctrl.invalid && (ctrl.dirty || ctrl.touched || this.submitting)) {
15327
+ errorCount++;
15328
+ }
15329
+ }
15330
+ }
15331
+ }
15332
+ }
15333
+ return errorCount;
15334
+ }
15335
+ getTabAriaControls(tab) {
15336
+ const ids = tab.sectionIds?.length ? tab.sectionIds : [tab.id];
15337
+ return ids.map((id) => `section-tabpanel-${id}`).join(' ');
15338
+ }
15339
+ getTabIdForSection(section) {
15340
+ if (!section || !section.id)
15341
+ return this.activeTabId;
15342
+ const matched = this.effectiveTabs.find((t) => (t.sectionIds || []).includes(section.id));
15343
+ return matched ? matched.id : this.activeTabId;
15344
+ }
15345
+ shouldHideSectionHeader(section) {
15346
+ if (this.effectiveLayoutMode !== 'tabs') {
15347
+ return false;
15348
+ }
15349
+ return this.effectiveHideSectionHeaderInTabs;
15350
+ }
14896
15351
  isSectionCollapsed(section) {
14897
15352
  const props = this.getSectionRuleProps(section);
14898
- const collapsible = props.collapsible !== undefined ? props.collapsible : section?.collapsible;
15353
+ const collapsible = props.collapsible !== undefined
15354
+ ? props.collapsible
15355
+ : (this.effectiveLayoutMode === 'accordion' || section?.collapsible);
14899
15356
  if (!collapsible) {
14900
15357
  return false;
14901
15358
  }
14902
15359
  const collapsed = props.collapsed !== undefined ? props.collapsed : section?.collapsed;
14903
- return !!collapsed;
15360
+ if (collapsed !== undefined) {
15361
+ return !!collapsed;
15362
+ }
15363
+ if (this.effectiveLayoutMode === 'accordion') {
15364
+ const sections = this.config?.sections || [];
15365
+ return sections.indexOf(section) > 0;
15366
+ }
15367
+ return false;
14904
15368
  }
14905
15369
  isSectionCollapsible(section) {
15370
+ if (this.effectiveLayoutMode === 'accordion') {
15371
+ return true;
15372
+ }
14906
15373
  const props = this.getSectionRuleProps(section);
14907
15374
  return (props.collapsible !== undefined
14908
15375
  ? props.collapsible
@@ -14963,7 +15430,36 @@ class PraxisDynamicForm {
14963
15430
  }
14964
15431
  getSectionAppearance(section) {
14965
15432
  const props = this.getSectionRuleProps(section);
14966
- return props.appearance ?? section.appearance;
15433
+ if (props.appearance) {
15434
+ return props.appearance;
15435
+ }
15436
+ if (section?.appearance) {
15437
+ return section.appearance;
15438
+ }
15439
+ if (this.sectionDefaultAppearance) {
15440
+ return this.sectionDefaultAppearance;
15441
+ }
15442
+ if (this.isCorporateDossierPreset() || this.isCompactPresentationPreset()) {
15443
+ return 'plain';
15444
+ }
15445
+ return undefined;
15446
+ }
15447
+ isSectionDividerEnabled(section) {
15448
+ const props = this.getSectionRuleProps(section);
15449
+ if (props.divider !== undefined) {
15450
+ return Boolean(props.divider);
15451
+ }
15452
+ if (section?.divider !== undefined) {
15453
+ return Boolean(section.divider);
15454
+ }
15455
+ if (this.sectionDivider !== undefined) {
15456
+ return Boolean(this.sectionDivider);
15457
+ }
15458
+ const appearance = this.getSectionAppearance(section);
15459
+ if (appearance === 'plain' && (this.isCorporateDossierPreset() || this.isCompactPresentationPreset())) {
15460
+ return true;
15461
+ }
15462
+ return false;
14967
15463
  }
14968
15464
  getSectionStepLabel(section) {
14969
15465
  const props = this.getSectionRuleProps(section);
@@ -15367,11 +15863,15 @@ class PraxisDynamicForm {
15367
15863
  getSectionClasses(section) {
15368
15864
  const key = section?.id || JSON.stringify(section?.rows?.map((row) => row.id) || []);
15369
15865
  const props = this.getSectionRuleProps(section);
15866
+ const sectionPreset = this.effectivePresentation ? this.getSectionPresentationPreset(section) : '';
15867
+ const isDivided = this.isSectionDividerEnabled(section);
15370
15868
  const signature = [
15371
15869
  this.getSectionAppearance(section) || '',
15870
+ isDivided ? 'divider' : '',
15372
15871
  section.cssClass || '',
15373
15872
  section.className || '',
15374
15873
  props.className || '',
15874
+ sectionPreset,
15375
15875
  ].join('|');
15376
15876
  const cached = this.sectionClassesCache.get(key);
15377
15877
  if (cached?.signature === signature) {
@@ -15381,6 +15881,11 @@ class PraxisDynamicForm {
15381
15881
  const appearance = this.getSectionAppearance(section);
15382
15882
  if (appearance)
15383
15883
  classes.push(`section-appearance-${appearance}`);
15884
+ if (isDivided)
15885
+ classes.push('section-has-divider');
15886
+ if (sectionPreset && sectionPreset !== 'default') {
15887
+ classes.push(`form-section--${sectionPreset}`);
15888
+ }
15384
15889
  const cssClass = section.cssClass;
15385
15890
  if (cssClass)
15386
15891
  classes.push(...cssClass.split(/\s+/).filter(Boolean));
@@ -15506,7 +16011,15 @@ class PraxisDynamicForm {
15506
16011
  event.stopPropagation();
15507
16012
  if (!this.isSectionCollapsible(section))
15508
16013
  return;
15509
- section.collapsed = !this.isSectionCollapsed(section);
16014
+ const willBeCollapsed = !this.isSectionCollapsed(section);
16015
+ if (!willBeCollapsed && this.effectiveLayoutMode === 'accordion' && !this.effectiveAccordionMulti) {
16016
+ for (const s of this.config.sections || []) {
16017
+ if (s !== section) {
16018
+ s.collapsed = true;
16019
+ }
16020
+ }
16021
+ }
16022
+ section.collapsed = willBeCollapsed;
15510
16023
  try {
15511
16024
  this.cdr.markForCheck();
15512
16025
  }
@@ -15999,6 +16512,9 @@ class PraxisDynamicForm {
15999
16512
  if (!normalizedActionId) {
16000
16513
  return;
16001
16514
  }
16515
+ if (!this.isRichContentActionAvailable(normalizedActionId)) {
16516
+ return;
16517
+ }
16002
16518
  if (normalizedActionId === 'submit' ||
16003
16519
  normalizedActionId === 'cancel' ||
16004
16520
  normalizedActionId === 'reset') {
@@ -16035,6 +16551,14 @@ class PraxisDynamicForm {
16035
16551
  if (!normalizedActionId) {
16036
16552
  return false;
16037
16553
  }
16554
+ if (this.effectiveDisabledMode === true) {
16555
+ return false;
16556
+ }
16557
+ if (normalizedActionId === 'submit' || normalizedActionId === 'reset') {
16558
+ if (this.effectiveReadonly || this.effectivePresentation) {
16559
+ return false;
16560
+ }
16561
+ }
16038
16562
  return true;
16039
16563
  }
16040
16564
  hasRichContentCapability(capabilityId) {
@@ -16045,6 +16569,10 @@ class PraxisDynamicForm {
16045
16569
  return this.mode === 'edit';
16046
16570
  case 'form.mode.view':
16047
16571
  return this.mode === 'view';
16572
+ case 'form.mode.presentation':
16573
+ return this.mode === 'presentation';
16574
+ case 'form.mode.dossier':
16575
+ return this.mode === 'dossier';
16048
16576
  case 'form.customization.enabled':
16049
16577
  return this.enableCustomization === true;
16050
16578
  case 'form.presentation.enabled':
@@ -16151,35 +16679,75 @@ class PraxisDynamicForm {
16151
16679
  async onSubmit() {
16152
16680
  if (this.effectiveReadonly || this.effectivePresentation)
16153
16681
  return;
16154
- if (this.submitting || this.submitPreparationInProgress)
16682
+ if (this.isDestroyed || this.submitting || this.submitPreparationInProgress)
16155
16683
  return;
16156
16684
  if (this.entityHydrationPending || this.entityReadFailed) {
16157
16685
  return;
16158
16686
  }
16687
+ const lifecycle = ++this.submitLifecycleSequence;
16688
+ this.activeSubmitLifecycle = lifecycle;
16689
+ this.activeSubmitAutomatic = this.usesAutomaticItemRevision();
16159
16690
  this.submitPreparationInProgress = true;
16160
16691
  try {
16161
- await this.prepareAndSubmit();
16692
+ await this.prepareAndSubmit(lifecycle);
16162
16693
  }
16163
16694
  finally {
16164
- this.submitPreparationInProgress = false;
16695
+ if (this.activeSubmitLifecycle === lifecycle)
16696
+ this.submitPreparationInProgress = false;
16165
16697
  }
16166
16698
  }
16167
- async prepareAndSubmit() {
16699
+ async prepareAndSubmit(lifecycle) {
16168
16700
  const submittingEntityId = this.resourceId;
16701
+ const binding = this.resourceRevisionBinding();
16702
+ const epoch = this.entityReadAttempt;
16703
+ const automatic = this.usesAutomaticItemRevision();
16704
+ const preparationForm = this.form;
16705
+ const preparationIsCurrent = () => {
16706
+ if (this.isDestroyed)
16707
+ return false;
16708
+ if (!automatic || this.isResourceRevisionCurrent(binding, epoch))
16709
+ return true;
16710
+ // A previously started hook can still hold the reused group. Its draft is no longer authoritative.
16711
+ if (preparationForm === this.form) {
16712
+ this.invalidateAutomaticSubmitUi();
16713
+ this.entityReadAttempt++;
16714
+ this.loadedResourceRevision = null;
16715
+ this.resourceRevisionInvalidated = true;
16716
+ }
16717
+ return false;
16718
+ };
16719
+ const waitForCurrentPreparation = async () => {
16720
+ const stable = await this.waitForReactiveDeterminationsBeforeSubmit(() => !this.isDestroyed && (!automatic || this.isResourceRevisionCurrent(binding, epoch)));
16721
+ const current = preparationIsCurrent();
16722
+ return current && stable;
16723
+ };
16169
16724
  this.clearSubmitFieldErrors();
16170
- if (!(await this.waitForReactiveDeterminationsBeforeSubmit()))
16725
+ if (!(await waitForCurrentPreparation()))
16171
16726
  return;
16172
16727
  // Hooks: beforeValidate
16173
16728
  try {
16174
16729
  await this.runHooks('beforeValidate');
16175
16730
  }
16176
16731
  catch { }
16177
- if (!(await this.waitForReactiveDeterminationsBeforeSubmit()))
16732
+ if (!preparationIsCurrent())
16733
+ return;
16734
+ if (!(await waitForCurrentPreparation()))
16178
16735
  return;
16179
16736
  if (this.form.invalid) {
16180
16737
  // UX: marcar todos como touched para exibir erros
16181
16738
  this.form.markAllAsTouched();
16182
16739
  this.form.updateValueAndValidity({ onlySelf: false, emitEvent: false });
16740
+ // UX Corporativa: Em layout por abas, se a aba ativa não tem erros, navega até a primeira aba com erro
16741
+ if (this.effectiveLayoutMode === 'tabs' && this.effectiveTabs.length > 0) {
16742
+ const currentTabHasErrors = this.effectiveTabs.some((t) => t.id === this.activeTabId && this.getTabErrorCount(t) > 0);
16743
+ if (!currentTabHasErrors) {
16744
+ const firstTabWithError = this.effectiveTabs.find((t) => this.getTabErrorCount(t) > 0);
16745
+ if (firstTabWithError && firstTabWithError.id !== this.activeTabId) {
16746
+ this.selectTab(firstTabWithError.id);
16747
+ this.cdr.detectChanges();
16748
+ }
16749
+ }
16750
+ }
16183
16751
  // Comportamento opcional conforme config.behavior
16184
16752
  const behavior = this.config.behavior || {};
16185
16753
  if (behavior.focusFirstError || behavior.scrollToErrors) {
@@ -16205,6 +16773,8 @@ class PraxisDynamicForm {
16205
16773
  await this.runHooks('afterValidate');
16206
16774
  }
16207
16775
  catch { }
16776
+ if (!preparationIsCurrent())
16777
+ return;
16208
16778
  return;
16209
16779
  }
16210
16780
  // Hooks: afterValidate (valid)
@@ -16212,11 +16782,15 @@ class PraxisDynamicForm {
16212
16782
  await this.runHooks('afterValidate');
16213
16783
  }
16214
16784
  catch { }
16215
- if (!(await this.waitForReactiveDeterminationsBeforeSubmit()))
16785
+ if (!preparationIsCurrent())
16786
+ return;
16787
+ if (!(await waitForCurrentPreparation()))
16216
16788
  return;
16217
16789
  // Hooks: beforeSubmit (cancelable) — must run BEFORE snapshotting form value
16218
16790
  try {
16219
16791
  const res = await this.runHooks('beforeSubmit');
16792
+ if (!preparationIsCurrent())
16793
+ return;
16220
16794
  if (res && res.stopped && res.stopped.outcome?.status === 'cancel') {
16221
16795
  // Cancel submission path — focus field if provided
16222
16796
  const field = res.stopped.outcome?.field;
@@ -16242,7 +16816,9 @@ class PraxisDynamicForm {
16242
16816
  }
16243
16817
  }
16244
16818
  catch { }
16245
- if (!(await this.waitForReactiveDeterminationsBeforeSubmit()))
16819
+ if (!preparationIsCurrent())
16820
+ return;
16821
+ if (!(await waitForCurrentPreparation()))
16246
16822
  return;
16247
16823
  if (this.form.invalid) {
16248
16824
  this.form.markAllAsTouched();
@@ -16255,6 +16831,8 @@ class PraxisDynamicForm {
16255
16831
  const rawFormData = this.form.getRawValue();
16256
16832
  const formData = this.prepareCurrentSubmitPayload(rawFormData);
16257
16833
  const operation = this.resolveSubmitOperation();
16834
+ if (!preparationIsCurrent())
16835
+ return;
16258
16836
  this.formSubmit.emit({
16259
16837
  stage: 'before',
16260
16838
  formData,
@@ -16264,6 +16842,8 @@ class PraxisDynamicForm {
16264
16842
  entityId: this.resourceId ?? undefined,
16265
16843
  });
16266
16844
  // Extra: pass snapshot to after hooks via extras when relevant
16845
+ if (!preparationIsCurrent())
16846
+ return;
16267
16847
  const req$ = this.buildSubmitRequest(formData, operation);
16268
16848
  // Mensagem de loading configurável durante o submit
16269
16849
  try {
@@ -16273,22 +16853,43 @@ class PraxisDynamicForm {
16273
16853
  }
16274
16854
  }
16275
16855
  catch { }
16856
+ const operationSnack = this._activeSnack;
16276
16857
  this.submitting = true;
16277
16858
  this.cdr.detectChanges();
16278
16859
  req$
16279
16860
  .pipe(takeUntil(this.destroy$), finalize(() => {
16861
+ try {
16862
+ operationSnack?.dismiss();
16863
+ }
16864
+ catch { }
16865
+ if (this._activeSnack === operationSnack)
16866
+ this._activeSnack = null;
16280
16867
  setTimeout(() => {
16868
+ if (this.activeSubmitLifecycle !== lifecycle)
16869
+ return;
16281
16870
  this.submitting = false;
16871
+ this.activeSubmitLifecycle = null;
16872
+ this.activeSubmitAutomatic = false;
16282
16873
  this.cdr.detectChanges();
16283
16874
  });
16284
16875
  }))
16285
16876
  .subscribe({
16286
16877
  next: (result) => {
16878
+ if (this.activeSubmitLifecycle !== lifecycle || automatic && !this.isResourceRevisionCurrent(binding, epoch))
16879
+ return;
16287
16880
  this.clearSubmitFieldErrors();
16881
+ try {
16882
+ const rp = (this.resourcePath || '').trim();
16883
+ if (rp) {
16884
+ this.optionRegistry?.invalidate(rp);
16885
+ }
16886
+ }
16887
+ catch { }
16288
16888
  // Encerrar loading
16289
16889
  try {
16290
- this._activeSnack?.dismiss();
16291
- this._activeSnack = null;
16890
+ operationSnack?.dismiss();
16891
+ if (this._activeSnack === operationSnack)
16892
+ this._activeSnack = null;
16292
16893
  }
16293
16894
  catch { }
16294
16895
  this.formSubmit.emit({
@@ -16330,10 +16931,13 @@ class PraxisDynamicForm {
16330
16931
  }
16331
16932
  },
16332
16933
  error: (error) => {
16934
+ if (this.activeSubmitLifecycle !== lifecycle || automatic && !this.isResourceRevisionCurrent(binding, epoch))
16935
+ return;
16333
16936
  // Encerrar loading
16334
16937
  try {
16335
- this._activeSnack?.dismiss();
16336
- this._activeSnack = null;
16938
+ operationSnack?.dismiss();
16939
+ if (this._activeSnack === operationSnack)
16940
+ this._activeSnack = null;
16337
16941
  }
16338
16942
  catch { }
16339
16943
  this.formSubmit.emit({
@@ -16357,7 +16961,8 @@ class PraxisDynamicForm {
16357
16961
  ...detail,
16358
16962
  }));
16359
16963
  this.applySubmitFieldErrors(normalizedError.details);
16360
- const errorMsg = this.resolveSubmitErrorMessage(normalizedError, operation);
16964
+ const errorMsg = error instanceof PraxisDynamicFormResourceRevisionReloadError
16965
+ ? error.message : this.resolveSubmitErrorMessage(normalizedError, operation);
16361
16966
  this.submitError = errorMsg;
16362
16967
  this.snackBar.open(errorMsg, undefined, {
16363
16968
  duration: 4000,
@@ -16368,7 +16973,9 @@ class PraxisDynamicForm {
16368
16973
  },
16369
16974
  });
16370
16975
  }
16371
- async waitForReactiveDeterminationsBeforeSubmit() {
16976
+ async waitForReactiveDeterminationsBeforeSubmit(stillCurrent = () => true) {
16977
+ if (!stillCurrent())
16978
+ return false;
16372
16979
  const pendingNotice = this.reactiveDeterminationRuntime.hasPending(this.form)
16373
16980
  ? this.snackBar.open(this.i18n.t('runtime.reactiveDetermination.submitPending', undefined, 'Aguarde a atualização dos campos relacionados antes de salvar.', PRAXIS_DYNAMIC_FORM_I18N_NAMESPACE), this.i18n.t('common.dismiss', undefined, 'Fechar', PRAXIS_DYNAMIC_FORM_I18N_NAMESPACE), { duration: 5000 })
16374
16981
  : null;
@@ -16377,6 +16984,8 @@ class PraxisDynamicForm {
16377
16984
  pendingNotice?.dismiss();
16378
16985
  }
16379
16986
  catch { }
16987
+ if (!stillCurrent())
16988
+ return false;
16380
16989
  if (stable)
16381
16990
  return true;
16382
16991
  this.snackBar.open(this.i18n.t('runtime.reactiveDetermination.submitUnsatisfied', undefined, 'Os campos relacionados não foram atualizados com sucesso. Revise os dados e tente novamente.', PRAXIS_DYNAMIC_FORM_I18N_NAMESPACE), this.i18n.t('common.dismiss', undefined, 'Fechar', PRAXIS_DYNAMIC_FORM_I18N_NAMESPACE), { duration: 7000 });
@@ -16912,7 +17521,7 @@ class PraxisDynamicForm {
16912
17521
  },
16913
17522
  },
16914
17523
  });
16915
- ref.applied$.pipe(takeUntil(this.destroy$)).subscribe((cfg) => {
17524
+ ref.applied$?.pipe(takeUntil(this.destroy$)).subscribe((cfg) => {
16916
17525
  try {
16917
17526
  this.debugLog('[PDF] settingsPanel.applied$', { hasCfg: !!cfg });
16918
17527
  }
@@ -16930,16 +17539,16 @@ class PraxisDynamicForm {
16930
17539
  appliedValues.next(cfg);
16931
17540
  }
16932
17541
  });
16933
- ref.closed$.pipe(take(1), takeUntil(this.destroy$)).subscribe(() => appliedValues.complete());
17542
+ ref.closed$?.pipe(take(1), takeUntil(this.destroy$)).subscribe(() => appliedValues.complete());
16934
17543
  // Handle reset from Settings Panel: clear persisted config so globals/user defaults apply
16935
- ref.reset$.pipe(takeUntil(this.destroy$)).subscribe(() => {
17544
+ ref.reset$?.pipe(takeUntil(this.destroy$)).subscribe(() => {
16936
17545
  try {
16937
17546
  this.debugLog('[PDF] settingsPanel.reset$');
16938
17547
  }
16939
17548
  catch { }
16940
17549
  this.clearDynamicFormEditorPersistence();
16941
17550
  });
16942
- ref.saved$.pipe(takeUntil(this.destroy$)).subscribe((cfg) => {
17551
+ ref.saved$?.pipe(takeUntil(this.destroy$)).subscribe((cfg) => {
16943
17552
  try {
16944
17553
  this.debugLog('[PDF] settingsPanel.saved$', { hasCfg: !!cfg });
16945
17554
  }
@@ -20166,6 +20775,9 @@ class PraxisDynamicForm {
20166
20775
  ngOnDestroy() {
20167
20776
  this.isDestroyed = true;
20168
20777
  this.cancelSchemaReads();
20778
+ this.entityReadAttempt++;
20779
+ this.invalidateAutomaticSubmitUi();
20780
+ this.activeSubmitLifecycle = null;
20169
20781
  this.resetSubmitErrorState();
20170
20782
  this.assistantSessions.removeContextSession(this.buildAiAssistantContextSnapshot());
20171
20783
  this.aiAssistantStateSubscription?.unsubscribe();
@@ -20203,6 +20815,12 @@ class PraxisDynamicForm {
20203
20815
  }
20204
20816
  applyConfigFromAdapter(nextConfig) {
20205
20817
  const raw = nextConfig;
20818
+ const identityConfig = raw && typeof raw === 'object'
20819
+ ? Object.prototype.hasOwnProperty.call(raw, 'config') ? raw['config']
20820
+ : Object.prototype.hasOwnProperty.call(raw, 'formConfig') ? raw['formConfig'] : raw
20821
+ : raw;
20822
+ if (formIdentityIssues(identityConfig).some(issue => issue.level === 'error'))
20823
+ return;
20206
20824
  const isCanonicalDocument = !!raw &&
20207
20825
  typeof raw === 'object' &&
20208
20826
  raw.kind === 'praxis.dynamic-form.editor';
@@ -20309,7 +20927,11 @@ class PraxisDynamicForm {
20309
20927
  };
20310
20928
  }
20311
20929
  captureCurrentPresentationSnapshot() {
20930
+ const preset = this.effectivePresentationPreset !== 'default'
20931
+ ? this.effectivePresentationPreset
20932
+ : undefined;
20312
20933
  return {
20934
+ ...(preset ? { preset, presentationPreset: preset } : {}),
20313
20935
  labelPosition: this.presentationVars.labelPosition,
20314
20936
  labelFontSize: this.parsePresentationCssNumber(this.presentationVars.labelSize),
20315
20937
  valueFontSize: this.parsePresentationCssNumber(this.presentationVars.valueSize),
@@ -20477,6 +21099,7 @@ class PraxisDynamicForm {
20477
21099
  this.configPatchChange.emit({
20478
21100
  inputPatch: {
20479
21101
  config: this.cloneFormConfigForPatch(this.config),
21102
+ ...(this.presentationPreset ? { presentationPreset: this.presentationPreset } : {}),
20480
21103
  ...bindings,
20481
21104
  },
20482
21105
  });
@@ -20532,7 +21155,7 @@ class PraxisDynamicForm {
20532
21155
  }
20533
21156
  });
20534
21157
  }
20535
- clearStoredPresentationSnapshots(modes = ['create', 'edit', 'view']) {
21158
+ clearStoredPresentationSnapshots(modes = ['create', 'edit', 'view', 'presentation', 'dossier']) {
20536
21159
  modes.forEach((mode) => {
20537
21160
  const presKey = this.formPresKey(mode);
20538
21161
  if (presKey) {
@@ -20563,6 +21186,10 @@ class PraxisDynamicForm {
20563
21186
  this.cancelSchemaReads();
20564
21187
  this.entityReadCancel$.next();
20565
21188
  this.isLoading = false;
21189
+ // Reset state for retry; only a successful new read clears a rejected revision.
21190
+ this.invalidateAutomaticSubmitUi();
21191
+ this.entityReadAttempt++;
21192
+ this.loadedResourceRevision = null;
20566
21193
  this.isInitialized = false;
20567
21194
  this.schemaCache = null;
20568
21195
  this.loadedEntityId = null;
@@ -20679,6 +21306,20 @@ class PraxisDynamicForm {
20679
21306
  locale: ctx.locale,
20680
21307
  apiOrigin: ctx.apiOrigin,
20681
21308
  };
21309
+ const disableCache = this.global.get('cache.disableSchemaCache');
21310
+ const cacheKey = this.dynamicForm.buildSchemaCacheKey({ ...schemaContext, baseUrl: ctx.baseUrl });
21311
+ if (!disableCache) {
21312
+ const compiled = this.dynamicForm.getCompiledSchema(cacheKey);
21313
+ if (compiled) {
21314
+ this.debugLog('[PDF] schema:fromL1Cache', { cacheKey });
21315
+ this.schemaCache = compiled.normalizedFields;
21316
+ this.schemaRootOperationId = compiled.schemaRootOperationId ?? null;
21317
+ this.schemaRootHooks = compiled.schemaRootHooks;
21318
+ this.schemaRootReactiveDeterminations = compiled.schemaRootReactiveDeterminations ?? [];
21319
+ this.lastSchemaMeta = { schemaId: compiled.schemaId, serverHash: compiled.serverHash, context: schemaContext };
21320
+ return compiled.normalizedFields;
21321
+ }
21322
+ }
20682
21323
  const loadingCtx = this.buildLoadingContext('schema', 'Carregando configuração...', true);
20683
21324
  this.beginLoading(loadingCtx);
20684
21325
  this.emitLoadingState('schema', 'loading', 'Carregando schema do formulário...');
@@ -20790,6 +21431,18 @@ class PraxisDynamicForm {
20790
21431
  const schemaId = buildSchemaId(schemaContext);
20791
21432
  this.lastSchemaMeta = { schemaId, serverHash: entry.schemaHash, context: schemaContext };
20792
21433
  this.schemaCache = defs;
21434
+ if (!disableCache) {
21435
+ this.dynamicForm.setCompiledSchema(cacheKey, {
21436
+ schemaId,
21437
+ serverHash: entry.schemaHash,
21438
+ rawSchema: entry.schema,
21439
+ normalizedFields: defs,
21440
+ schemaRootOperationId: this.schemaRootOperationId,
21441
+ schemaRootHooks: this.schemaRootHooks,
21442
+ schemaRootReactiveDeterminations: this.schemaRootReactiveDeterminations,
21443
+ compiledAt: Date.now(),
21444
+ });
21445
+ }
20793
21446
  this.emitLoadingState('schema', 'success', 'Schema carregado.');
20794
21447
  // Persist meta for future ETag verifications
20795
21448
  try {
@@ -20830,6 +21483,19 @@ class PraxisDynamicForm {
20830
21483
  this.endLoading(loadingCtx);
20831
21484
  }
20832
21485
  }
21486
+ /**
21487
+ * Invalida o cache de schema compilado para a instância atual e força
21488
+ * novo carregamento na próxima requisição.
21489
+ */
21490
+ invalidateSchemaCache() {
21491
+ try {
21492
+ const ctx = this.buildSchemaContext();
21493
+ const cacheKey = this.dynamicForm.buildSchemaCacheKey({ ...ctx, baseUrl: ctx.baseUrl });
21494
+ this.dynamicForm.invalidateCompiledSchema(cacheKey);
21495
+ }
21496
+ catch { }
21497
+ this.schemaCache = null;
21498
+ }
20833
21499
  isReactiveValidationEnabled() {
20834
21500
  if (this.reactiveValidation !== null)
20835
21501
  return !!this.reactiveValidation;
@@ -20962,7 +21628,7 @@ class PraxisDynamicForm {
20962
21628
  }
20963
21629
  }
20964
21630
  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 });
20965
- 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 <div #entityReadRegion class=\"entity-read-region\" tabindex=\"-1\" role=\"region\" [attr.aria-label]=\"entityReadText('region')\">\n <span class=\"cdk-visually-hidden\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">{{ entityReadStatusText() }}</span>\n @if (entityHydrationPending || entityReadFailed) {\n <div class=\"entity-read-feedback\" data-testid=\"form-entity-read-feedback\">\n @if (entityHydrationPending) {\n <mat-progress-spinner diameter=\"28\" mode=\"indeterminate\" aria-hidden=\"true\"></mat-progress-spinner>\n <p aria-hidden=\"true\">{{ entityReadText('loading') }}</p>\n } @else {\n <mat-icon [praxisIcon]=\"'error_outline'\" aria-hidden=\"true\"></mat-icon>\n <p aria-hidden=\"true\">{{ entityReadText('error') }}</p>\n <button mat-stroked-button type=\"button\" (click)=\"retryEntityRead(entityReadRegion)\">{{ entityReadText('retry') }}</button>\n }\n </div>\n }\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting || entityHydrationPending ? 'true' : null\"\n [style.opacity]=\"entityHydrationPending || entityReadFailed ? '0' : null\"\n [style.transition]=\"entityHydrationPending || entityReadFailed ? 'none' : null\"\n [attr.inert]=\"entityHydrationPending || entityReadFailed ? '' : null\"\n [attr.aria-hidden]=\"entityHydrationPending || entityReadFailed ? '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 </div>\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 || entityHydrationPending || entityReadFailed\"\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}.entity-read-region{position:relative;min-width:0}.entity-read-feedback{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1rem;padding:2rem 1rem;box-sizing:border-box;text-align:center;color:var(--md-sys-color-on-surface)}.entity-read-feedback p{margin:0;max-width:40ch}.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, 0);place-items:center;padding:var(--pdx-form-context-empty-padding, 0)}.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"], outputs: ["nodeAction"] }] });
21631
+ 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", layoutMode: "layoutMode", formLayout: "formLayout", 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", presentationPreset: "presentationPreset", sectionDefaultAppearance: "sectionDefaultAppearance", sectionDivider: "sectionDivider", 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", tabChange: "tabChange", tabSelected: "tabSelected" }, 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 <div #entityReadRegion class=\"entity-read-region\" tabindex=\"-1\" role=\"region\" [attr.aria-label]=\"entityReadText('region')\">\n <span class=\"cdk-visually-hidden\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">{{ entityReadStatusText() }}</span>\n @if (entityHydrationPending || entityReadFailed) {\n <div class=\"entity-read-feedback\" data-testid=\"form-entity-read-feedback\">\n @if (entityHydrationPending) {\n <mat-progress-spinner diameter=\"28\" mode=\"indeterminate\" aria-hidden=\"true\"></mat-progress-spinner>\n <p aria-hidden=\"true\">{{ entityReadText('loading') }}</p>\n } @else {\n <mat-icon [praxisIcon]=\"'error_outline'\" aria-hidden=\"true\"></mat-icon>\n <p aria-hidden=\"true\">{{ entityReadText('error') }}</p>\n <button mat-stroked-button type=\"button\" (click)=\"retryEntityRead(entityReadRegion)\">{{ entityReadText('retry') }}</button>\n }\n </div>\n }\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting || entityHydrationPending ? 'true' : null\"\n [style.opacity]=\"entityHydrationPending || entityReadFailed ? '0' : null\"\n [style.transition]=\"entityHydrationPending || entityReadFailed ? 'none' : null\"\n [attr.inert]=\"entityHydrationPending || entityReadFailed ? '' : null\"\n [attr.aria-hidden]=\"entityHydrationPending || entityReadFailed ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\"\n [class.praxis-dynamic-form--presentation]=\"effectivePresentation\"\n [class.readonly-mode]=\"effectiveReadonly\"\n [attr.data-presentation-preset]=\"effectivePresentation ? effectivePresentationPreset : null\"\n [class.praxis-dynamic-form--corporate-dossier]=\"isCorporateDossierPreset()\"\n [class.praxis-dynamic-form--editorial-card]=\"isEditorialCardPreset()\"\n [class.praxis-dynamic-form--compact-presentation]=\"isCompactPresentationPreset()\"\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 <!-- Tab Layout Navigation Bar -->\n @if (effectiveLayoutMode === 'tabs' && effectiveTabs.length > 1) {\n <nav class=\"prx-form-tabs\" [attr.data-appearance]=\"effectiveTabsAppearance\" role=\"tablist\" aria-label=\"Navega\u00E7\u00E3o em abas do formul\u00E1rio\">\n <div class=\"prx-form-tabs__tablist prx-form-tabs__tablist--scrollable\">\n @for (tab of effectiveTabs; track tab.id) {\n <button\n type=\"button\"\n role=\"tab\"\n class=\"prx-form-tabs__tab\"\n [class.prx-form-tabs__tab--active]=\"activeTabId === tab.id\"\n [attr.aria-selected]=\"activeTabId === tab.id\"\n [attr.aria-controls]=\"getTabAriaControls(tab)\"\n [attr.id]=\"'tab-' + tab.id\"\n [disabled]=\"tab.disabled\"\n [matTooltip]=\"tab.tooltip || null\"\n [matTooltipDisabled]=\"!tab.tooltip\"\n (click)=\"selectTab(tab.id)\"\n >\n @if (tab.icon) {\n <mat-icon class=\"prx-form-tabs__tab-icon\" [praxisIcon]=\"tab.icon\" aria-hidden=\"true\"></mat-icon>\n }\n <span class=\"prx-form-tabs__tab-label\">{{ tab.label }}</span>\n @if (tab.badge != null) {\n <span class=\"prx-form-tabs__tab-badge\">{{ tab.badge }}</span>\n }\n @if (getTabErrorCount(tab) > 0) {\n <span class=\"prx-form-tabs__tab-error-badge\" [attr.aria-label]=\"getTabErrorCount(tab) + ' erros na aba'\">\n {{ getTabErrorCount(tab) }}\n </span>\n }\n </button>\n }\n </div>\n </nav>\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\" [hidden]=\"!isSectionInActiveTab(section)\"\n [attr.role]=\"effectiveLayoutMode === 'tabs' ? 'tabpanel' : null\"\n [attr.id]=\"effectiveLayoutMode === 'tabs' ? ('section-tabpanel-' + section.id) : null\"\n [attr.aria-labelledby]=\"effectiveLayoutMode === 'tabs' ? ('tab-' + (getTabIdForSection(section) || section.id)) : null\">\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 [attr.data-section-divider]=\"isSectionDividerEnabled(section) ? 'true' : null\"\n [attr.data-presentation-preset]=\"effectivePresentation ? getSectionPresentationPreset(section) : null\"\n [class.form-section--corporate-dossier]=\"isSectionCorporateDossier(section)\"\n [class.form-section--editorial-card]=\"isSectionEditorialCard(section)\"\n [class.form-section--compact-presentation]=\"isSectionCompactPresentation(section)\"\n [style.marginBottom.px]=\"!isLastVisibleSection(section) ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n @if (!shouldHideSectionHeader(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\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 </div>\n }\n @if (showAiAssistant && !enableCustomization && (mode === 'view' || mode === 'presentation' || mode === 'dossier') && !shouldShowContextEmptyState()) {\n <div class=\"ai-floating-assistant\">\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"compact\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading || entityHydrationPending || entityReadFailed\"\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}.entity-read-region{position:relative;min-width:0}.entity-read-feedback{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1rem;padding:2rem 1rem;box-sizing:border-box;text-align:center;color:var(--md-sys-color-on-surface)}.entity-read-feedback p{margin:0;max-width:40ch}.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}}.praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section:not(.section-appearance-plain),.praxis-dynamic-form .form-section.form-section--corporate-dossier:not(.section-appearance-plain),.praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier]:not(.section-appearance-plain){background:var(--md-sys-color-surface-container-low, #f8f9fa);border:1px solid var(--md-sys-color-outline-variant, #e0e2ec);border-radius:16px;padding:16px 20px;box-shadow:0 1px 3px #0000000a}.praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section .section-heading,.praxis-dynamic-form .form-section.form-section--corporate-dossier .section-heading,.praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier] .section-heading{margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--md-sys-color-outline-variant, #e0e2ec)}.praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section .section-title,.praxis-dynamic-form .form-section.form-section--corporate-dossier .section-title,.praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier] .section-title{font-size:.88rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--md-sys-color-primary, #005ac1)}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation{padding:8px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .form-row:last-child .praxis-presentation,:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation:last-child,:host ::ng-deep .form-section--corporate-dossier .form-row:last-child .praxis-presentation,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation:last-child,:host ::ng-deep [data-presentation-preset=corporate-dossier] .form-row:last-child .praxis-presentation,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation:last-child{border-bottom:none}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation__label,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation__label,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation__label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--md-sys-color-on-surface-variant, #44474f);margin-bottom:3px}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation__value,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation__value,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation__value{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface, #1a1c1e);line-height:1.4}.praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section:not(.section-appearance-plain),.praxis-dynamic-form .form-section.form-section--editorial-card:not(.section-appearance-plain),.praxis-dynamic-form .form-section[data-presentation-preset=editorial-card]:not(.section-appearance-plain){background:var(--pfx-editorial-form-surface, var(--md-sys-color-surface-container-low, #ffffff));border:1px solid var(--pfx-editorial-form-border, var(--md-sys-color-outline-variant, #e0e2ec));border-radius:20px;padding:24px;box-shadow:0 2px 8px #0000000d}.praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section .section-heading,.praxis-dynamic-form .form-section.form-section--editorial-card .section-heading,.praxis-dynamic-form .form-section[data-presentation-preset=editorial-card] .section-heading{margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 40%,transparent)}.praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section .section-title,.praxis-dynamic-form .form-section.form-section--editorial-card .section-title,.praxis-dynamic-form .form-section[data-presentation-preset=editorial-card] .section-title{font-size:1.15rem;font-weight:700;color:var(--pfx-editorial-form-accent, var(--md-sys-color-primary, #005ac1))}:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation,:host ::ng-deep .form-section--editorial-card .praxis-presentation,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation{padding:10px 0;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 35%,transparent)}:host ::ng-deep .praxis-dynamic-form--editorial-card .form-row:last-child .praxis-presentation,:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation:last-child,:host ::ng-deep .form-section--editorial-card .form-row:last-child .praxis-presentation,:host ::ng-deep .form-section--editorial-card .praxis-presentation:last-child,:host ::ng-deep [data-presentation-preset=editorial-card] .form-row:last-child .praxis-presentation,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation:last-child{border-bottom:none}:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation__label,:host ::ng-deep .form-section--editorial-card .praxis-presentation__label,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation__label{font-size:.8rem;font-weight:500;color:var(--pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant, #44474f));margin-bottom:4px}:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation__value,:host ::ng-deep .form-section--editorial-card .praxis-presentation__value,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation__value{font-size:1rem;font-weight:600;color:var(--pfx-editorial-form-text, var(--md-sys-color-on-surface, #1a1c1e));line-height:1.5}.praxis-dynamic-form.praxis-dynamic-form--compact-presentation .form-section:not(.section-appearance-plain),.praxis-dynamic-form .form-section.form-section--compact-presentation:not(.section-appearance-plain),.praxis-dynamic-form .form-section[data-presentation-preset=compact-presentation]:not(.section-appearance-plain){background:transparent;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 50%,transparent);border-radius:8px;padding:10px 14px;box-shadow:none}.praxis-dynamic-form.praxis-dynamic-form--compact-presentation .form-section .section-heading,.praxis-dynamic-form .form-section.form-section--compact-presentation .section-heading,.praxis-dynamic-form .form-section[data-presentation-preset=compact-presentation] .section-heading{margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 25%,transparent)}.praxis-dynamic-form.praxis-dynamic-form--compact-presentation .form-section .section-title,.praxis-dynamic-form .form-section.form-section--compact-presentation .section-title,.praxis-dynamic-form .form-section[data-presentation-preset=compact-presentation] .section-title{font-size:.82rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant, #44474f)}:host ::ng-deep .praxis-dynamic-form--compact-presentation .praxis-presentation,:host ::ng-deep .form-section--compact-presentation .praxis-presentation,:host ::ng-deep [data-presentation-preset=compact-presentation] .praxis-presentation{padding:4px 0;border-bottom:none}:host ::ng-deep .praxis-dynamic-form--compact-presentation .praxis-presentation__label,:host ::ng-deep .form-section--compact-presentation .praxis-presentation__label,:host ::ng-deep [data-presentation-preset=compact-presentation] .praxis-presentation__label{font-size:.72rem;font-weight:600;color:var(--md-sys-color-on-surface-variant, #44474f);margin-bottom:2px}:host ::ng-deep .praxis-dynamic-form--compact-presentation .praxis-presentation__value,:host ::ng-deep .form-section--compact-presentation .praxis-presentation__value,:host ::ng-deep [data-presentation-preset=compact-presentation] .praxis-presentation__value{font-size:.88rem;font-weight:500;color:var(--md-sys-color-on-surface, #1a1c1e);line-height:1.35}:host-context(.mdc-theme-dark) .praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section.form-section--corporate-dossier:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier]:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section.form-section--corporate-dossier:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier]:not(.section-appearance-plain){background:var(--md-sys-color-surface-container-low);border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);box-shadow:0 2px 8px #0000004d}:host-context(.mdc-theme-dark) .praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section.form-section--editorial-card:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=editorial-card]:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section.form-section--editorial-card:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=editorial-card]:not(.section-appearance-plain){background:var(--pfx-editorial-form-surface, var(--md-sys-color-surface-container-low));border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);box-shadow:0 4px 16px #0006}.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-width:0;border-radius:0;padding:0;background:transparent;box-shadow:none}.praxis-dynamic-form .form-section.section-appearance-plain.section-has-divider{padding-bottom:16px;border-bottom:1px solid var(--pfx-form-section-divider, var(--md-sys-color-outline-variant, #e0e2ec))}.praxis-dynamic-form .section-drop-wrapper:last-of-type>.form-section.section-appearance-plain.section-has-divider,.praxis-dynamic-form>.form-section.section-appearance-plain.section-has-divider:last-of-type{border-bottom:none;padding-bottom:0}.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, 0);place-items:center;padding:var(--pdx-form-context-empty-padding, 0)}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}.prx-form-tabs{display:block;margin-bottom:16px;max-width:100%}.prx-form-tabs__tablist{display:flex;flex-wrap:wrap;align-items:center;gap:8px;max-width:100%}.prx-form-tabs__tablist--scrollable{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding:4px 2px}.prx-form-tabs__tablist--scrollable::-webkit-scrollbar{display:none}.prx-form-tabs__tab{display:inline-flex;align-items:center;gap:8px;min-width:0;padding:8px 14px;border-radius:999px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .12));background:color-mix(in srgb,var(--md-sys-color-surface, transparent) 40%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);font-family:inherit;font-size:.84rem;font-weight:500;cursor:pointer;white-space:nowrap;flex-shrink:0;-webkit-user-select:none;user-select:none;transition:all .2s cubic-bezier(.2,0,0,1)}.prx-form-tabs__tab:hover:not(:disabled):not(.prx-form-tabs__tab--active){background:var(--md-sys-color-surface-container-high, rgba(0, 0, 0, .05));border-color:var(--md-sys-color-outline, rgba(0, 0, 0, .24));color:var(--md-sys-color-on-surface)}.prx-form-tabs__tab:focus-visible{outline:2px solid var(--md-sys-color-primary, #005ac1);outline-offset:2px}.prx-form-tabs__tab:disabled{cursor:not-allowed;opacity:.45}.prx-form-tabs__tab--active{background:var(--md-sys-color-primary-container, color-mix(in srgb, var(--md-sys-color-primary, #005ac1) 16%, var(--md-sys-color-surface-container-high, #2b2930)));color:var(--md-sys-color-on-primary-container, var(--md-sys-color-primary, #005ac1));border-color:transparent;font-weight:600;box-shadow:0 1px 3px #00000014}.prx-form-tabs__tab-icon{font-size:18px;width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center}.prx-form-tabs__tab-badge{display:inline-flex;align-items:center;justify-content:center;padding:1px 7px;font-size:.72rem;font-weight:600;border-radius:999px;background:color-mix(in srgb,currentColor 14%,transparent)}.prx-form-tabs__tab-error-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;font-size:.7rem;font-weight:700;background:var(--md-sys-color-error, #ba1a1a);color:var(--md-sys-color-on-error, #ffffff);box-shadow:0 1px 2px #0003}.prx-form-tabs[data-appearance=underline]{border-bottom:1px solid var(--md-sys-color-outline-variant, #cac4d0)}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tablist{gap:16px;padding-bottom:0}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tab{border:none;border-radius:0;border-bottom:2px solid transparent;background:transparent;padding:8px 4px 10px;margin-bottom:-1px}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tab:hover:not(:disabled):not(.prx-form-tabs__tab--active){background:transparent;border-bottom-color:var(--md-sys-color-outline-variant, #cac4d0)}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tab--active{background:transparent;box-shadow:none;border-bottom-color:var(--md-sys-color-primary, #005ac1);color:var(--md-sys-color-primary, #005ac1)}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tablist{background:var(--md-sys-color-surface-container, rgba(0, 0, 0, .04));border-radius:12px;padding:4px;gap:4px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tab{border:none;border-radius:8px;padding:6px 12px;background:transparent}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tab:hover:not(:disabled):not(.prx-form-tabs__tab--active){background:color-mix(in srgb,currentColor 8%,transparent)}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tab--active{background:var(--md-sys-color-surface, #ffffff);color:var(--md-sys-color-primary, #005ac1);box-shadow:0 1px 3px #0000001f}.section-drop-wrapper[hidden]{display:none!important}\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"], outputs: ["nodeAction"] }] });
20966
21632
  }
20967
21633
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicForm, decorators: [{
20968
21634
  type: Component,
@@ -20984,7 +21650,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
20984
21650
  EmptyStateCardComponent,
20985
21651
  PraxisAiAssistantShellComponent,
20986
21652
  PraxisRichContent,
20987
- ], 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 <div #entityReadRegion class=\"entity-read-region\" tabindex=\"-1\" role=\"region\" [attr.aria-label]=\"entityReadText('region')\">\n <span class=\"cdk-visually-hidden\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">{{ entityReadStatusText() }}</span>\n @if (entityHydrationPending || entityReadFailed) {\n <div class=\"entity-read-feedback\" data-testid=\"form-entity-read-feedback\">\n @if (entityHydrationPending) {\n <mat-progress-spinner diameter=\"28\" mode=\"indeterminate\" aria-hidden=\"true\"></mat-progress-spinner>\n <p aria-hidden=\"true\">{{ entityReadText('loading') }}</p>\n } @else {\n <mat-icon [praxisIcon]=\"'error_outline'\" aria-hidden=\"true\"></mat-icon>\n <p aria-hidden=\"true\">{{ entityReadText('error') }}</p>\n <button mat-stroked-button type=\"button\" (click)=\"retryEntityRead(entityReadRegion)\">{{ entityReadText('retry') }}</button>\n }\n </div>\n }\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting || entityHydrationPending ? 'true' : null\"\n [style.opacity]=\"entityHydrationPending || entityReadFailed ? '0' : null\"\n [style.transition]=\"entityHydrationPending || entityReadFailed ? 'none' : null\"\n [attr.inert]=\"entityHydrationPending || entityReadFailed ? '' : null\"\n [attr.aria-hidden]=\"entityHydrationPending || entityReadFailed ? '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 </div>\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 || entityHydrationPending || entityReadFailed\"\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}.entity-read-region{position:relative;min-width:0}.entity-read-feedback{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1rem;padding:2rem 1rem;box-sizing:border-box;text-align:center;color:var(--md-sys-color-on-surface)}.entity-read-feedback p{margin:0;max-width:40ch}.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, 0);place-items:center;padding:var(--pdx-form-context-empty-padding, 0)}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}\n"] }]
21653
+ ], 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 <div #entityReadRegion class=\"entity-read-region\" tabindex=\"-1\" role=\"region\" [attr.aria-label]=\"entityReadText('region')\">\n <span class=\"cdk-visually-hidden\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">{{ entityReadStatusText() }}</span>\n @if (entityHydrationPending || entityReadFailed) {\n <div class=\"entity-read-feedback\" data-testid=\"form-entity-read-feedback\">\n @if (entityHydrationPending) {\n <mat-progress-spinner diameter=\"28\" mode=\"indeterminate\" aria-hidden=\"true\"></mat-progress-spinner>\n <p aria-hidden=\"true\">{{ entityReadText('loading') }}</p>\n } @else {\n <mat-icon [praxisIcon]=\"'error_outline'\" aria-hidden=\"true\"></mat-icon>\n <p aria-hidden=\"true\">{{ entityReadText('error') }}</p>\n <button mat-stroked-button type=\"button\" (click)=\"retryEntityRead(entityReadRegion)\">{{ entityReadText('retry') }}</button>\n }\n </div>\n }\n <form #formHost (ngSubmit)=\"onSubmit()\" [attr.aria-busy]=\"submitting || entityHydrationPending ? 'true' : null\"\n [style.opacity]=\"entityHydrationPending || entityReadFailed ? '0' : null\"\n [style.transition]=\"entityHydrationPending || entityReadFailed ? 'none' : null\"\n [attr.inert]=\"entityHydrationPending || entityReadFailed ? '' : null\"\n [attr.aria-hidden]=\"entityHydrationPending || entityReadFailed ? 'true' : null\"\n [attr.aria-label]=\"'Formul\u00E1rio ' + (config.metadata?.version || '')\" [class.canvas-mode-enabled]=\"enableCustomization\"\n [class.presentation-mode]=\"effectivePresentation\"\n [class.praxis-dynamic-form--presentation]=\"effectivePresentation\"\n [class.readonly-mode]=\"effectiveReadonly\"\n [attr.data-presentation-preset]=\"effectivePresentation ? effectivePresentationPreset : null\"\n [class.praxis-dynamic-form--corporate-dossier]=\"isCorporateDossierPreset()\"\n [class.praxis-dynamic-form--editorial-card]=\"isEditorialCardPreset()\"\n [class.praxis-dynamic-form--compact-presentation]=\"isCompactPresentationPreset()\"\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 <!-- Tab Layout Navigation Bar -->\n @if (effectiveLayoutMode === 'tabs' && effectiveTabs.length > 1) {\n <nav class=\"prx-form-tabs\" [attr.data-appearance]=\"effectiveTabsAppearance\" role=\"tablist\" aria-label=\"Navega\u00E7\u00E3o em abas do formul\u00E1rio\">\n <div class=\"prx-form-tabs__tablist prx-form-tabs__tablist--scrollable\">\n @for (tab of effectiveTabs; track tab.id) {\n <button\n type=\"button\"\n role=\"tab\"\n class=\"prx-form-tabs__tab\"\n [class.prx-form-tabs__tab--active]=\"activeTabId === tab.id\"\n [attr.aria-selected]=\"activeTabId === tab.id\"\n [attr.aria-controls]=\"getTabAriaControls(tab)\"\n [attr.id]=\"'tab-' + tab.id\"\n [disabled]=\"tab.disabled\"\n [matTooltip]=\"tab.tooltip || null\"\n [matTooltipDisabled]=\"!tab.tooltip\"\n (click)=\"selectTab(tab.id)\"\n >\n @if (tab.icon) {\n <mat-icon class=\"prx-form-tabs__tab-icon\" [praxisIcon]=\"tab.icon\" aria-hidden=\"true\"></mat-icon>\n }\n <span class=\"prx-form-tabs__tab-label\">{{ tab.label }}</span>\n @if (tab.badge != null) {\n <span class=\"prx-form-tabs__tab-badge\">{{ tab.badge }}</span>\n }\n @if (getTabErrorCount(tab) > 0) {\n <span class=\"prx-form-tabs__tab-error-badge\" [attr.aria-label]=\"getTabErrorCount(tab) + ' erros na aba'\">\n {{ getTabErrorCount(tab) }}\n </span>\n }\n </button>\n }\n </div>\n </nav>\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\" [hidden]=\"!isSectionInActiveTab(section)\"\n [attr.role]=\"effectiveLayoutMode === 'tabs' ? 'tabpanel' : null\"\n [attr.id]=\"effectiveLayoutMode === 'tabs' ? ('section-tabpanel-' + section.id) : null\"\n [attr.aria-labelledby]=\"effectiveLayoutMode === 'tabs' ? ('tab-' + (getTabIdForSection(section) || section.id)) : null\">\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 [attr.data-section-divider]=\"isSectionDividerEnabled(section) ? 'true' : null\"\n [attr.data-presentation-preset]=\"effectivePresentation ? getSectionPresentationPreset(section) : null\"\n [class.form-section--corporate-dossier]=\"isSectionCorporateDossier(section)\"\n [class.form-section--editorial-card]=\"isSectionEditorialCard(section)\"\n [class.form-section--compact-presentation]=\"isSectionCompactPresentation(section)\"\n [style.marginBottom.px]=\"!isLastVisibleSection(section) ? getSectionGapBottom(section) : null\" [ngClass]=\"getSectionClasses(section)\"\n [ngStyle]=\"getSectionStyles(section)\">\n @if (!shouldHideSectionHeader(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\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 </div>\n }\n @if (showAiAssistant && !enableCustomization && (mode === 'view' || mode === 'presentation' || mode === 'dossier') && !shouldShowContextEmptyState()) {\n <div class=\"ai-floating-assistant\">\n <button type=\"button\" praxisIconButton=\"auto_awesome\" size=\"compact\" (click)=\"openAiAssistant()\" [disabled]=\"isLoading || entityHydrationPending || entityReadFailed\"\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}.entity-read-region{position:relative;min-width:0}.entity-read-feedback{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:1rem;padding:2rem 1rem;box-sizing:border-box;text-align:center;color:var(--md-sys-color-on-surface)}.entity-read-feedback p{margin:0;max-width:40ch}.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}}.praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section:not(.section-appearance-plain),.praxis-dynamic-form .form-section.form-section--corporate-dossier:not(.section-appearance-plain),.praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier]:not(.section-appearance-plain){background:var(--md-sys-color-surface-container-low, #f8f9fa);border:1px solid var(--md-sys-color-outline-variant, #e0e2ec);border-radius:16px;padding:16px 20px;box-shadow:0 1px 3px #0000000a}.praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section .section-heading,.praxis-dynamic-form .form-section.form-section--corporate-dossier .section-heading,.praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier] .section-heading{margin-bottom:12px;padding-bottom:8px;border-bottom:1px solid var(--md-sys-color-outline-variant, #e0e2ec)}.praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section .section-title,.praxis-dynamic-form .form-section.form-section--corporate-dossier .section-title,.praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier] .section-title{font-size:.88rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--md-sys-color-primary, #005ac1)}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation{padding:8px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .form-row:last-child .praxis-presentation,:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation:last-child,:host ::ng-deep .form-section--corporate-dossier .form-row:last-child .praxis-presentation,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation:last-child,:host ::ng-deep [data-presentation-preset=corporate-dossier] .form-row:last-child .praxis-presentation,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation:last-child{border-bottom:none}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation__label,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation__label,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation__label{font-size:.74rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--md-sys-color-on-surface-variant, #44474f);margin-bottom:3px}:host ::ng-deep .praxis-dynamic-form--corporate-dossier .praxis-presentation__value,:host ::ng-deep .form-section--corporate-dossier .praxis-presentation__value,:host ::ng-deep [data-presentation-preset=corporate-dossier] .praxis-presentation__value{font-size:.95rem;font-weight:600;color:var(--md-sys-color-on-surface, #1a1c1e);line-height:1.4}.praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section:not(.section-appearance-plain),.praxis-dynamic-form .form-section.form-section--editorial-card:not(.section-appearance-plain),.praxis-dynamic-form .form-section[data-presentation-preset=editorial-card]:not(.section-appearance-plain){background:var(--pfx-editorial-form-surface, var(--md-sys-color-surface-container-low, #ffffff));border:1px solid var(--pfx-editorial-form-border, var(--md-sys-color-outline-variant, #e0e2ec));border-radius:20px;padding:24px;box-shadow:0 2px 8px #0000000d}.praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section .section-heading,.praxis-dynamic-form .form-section.form-section--editorial-card .section-heading,.praxis-dynamic-form .form-section[data-presentation-preset=editorial-card] .section-heading{margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 40%,transparent)}.praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section .section-title,.praxis-dynamic-form .form-section.form-section--editorial-card .section-title,.praxis-dynamic-form .form-section[data-presentation-preset=editorial-card] .section-title{font-size:1.15rem;font-weight:700;color:var(--pfx-editorial-form-accent, var(--md-sys-color-primary, #005ac1))}:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation,:host ::ng-deep .form-section--editorial-card .praxis-presentation,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation{padding:10px 0;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 35%,transparent)}:host ::ng-deep .praxis-dynamic-form--editorial-card .form-row:last-child .praxis-presentation,:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation:last-child,:host ::ng-deep .form-section--editorial-card .form-row:last-child .praxis-presentation,:host ::ng-deep .form-section--editorial-card .praxis-presentation:last-child,:host ::ng-deep [data-presentation-preset=editorial-card] .form-row:last-child .praxis-presentation,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation:last-child{border-bottom:none}:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation__label,:host ::ng-deep .form-section--editorial-card .praxis-presentation__label,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation__label{font-size:.8rem;font-weight:500;color:var(--pfx-editorial-form-text-muted, var(--md-sys-color-on-surface-variant, #44474f));margin-bottom:4px}:host ::ng-deep .praxis-dynamic-form--editorial-card .praxis-presentation__value,:host ::ng-deep .form-section--editorial-card .praxis-presentation__value,:host ::ng-deep [data-presentation-preset=editorial-card] .praxis-presentation__value{font-size:1rem;font-weight:600;color:var(--pfx-editorial-form-text, var(--md-sys-color-on-surface, #1a1c1e));line-height:1.5}.praxis-dynamic-form.praxis-dynamic-form--compact-presentation .form-section:not(.section-appearance-plain),.praxis-dynamic-form .form-section.form-section--compact-presentation:not(.section-appearance-plain),.praxis-dynamic-form .form-section[data-presentation-preset=compact-presentation]:not(.section-appearance-plain){background:transparent;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 50%,transparent);border-radius:8px;padding:10px 14px;box-shadow:none}.praxis-dynamic-form.praxis-dynamic-form--compact-presentation .form-section .section-heading,.praxis-dynamic-form .form-section.form-section--compact-presentation .section-heading,.praxis-dynamic-form .form-section[data-presentation-preset=compact-presentation] .section-heading{margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #e0e2ec) 25%,transparent)}.praxis-dynamic-form.praxis-dynamic-form--compact-presentation .form-section .section-title,.praxis-dynamic-form .form-section.form-section--compact-presentation .section-title,.praxis-dynamic-form .form-section[data-presentation-preset=compact-presentation] .section-title{font-size:.82rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant, #44474f)}:host ::ng-deep .praxis-dynamic-form--compact-presentation .praxis-presentation,:host ::ng-deep .form-section--compact-presentation .praxis-presentation,:host ::ng-deep [data-presentation-preset=compact-presentation] .praxis-presentation{padding:4px 0;border-bottom:none}:host ::ng-deep .praxis-dynamic-form--compact-presentation .praxis-presentation__label,:host ::ng-deep .form-section--compact-presentation .praxis-presentation__label,:host ::ng-deep [data-presentation-preset=compact-presentation] .praxis-presentation__label{font-size:.72rem;font-weight:600;color:var(--md-sys-color-on-surface-variant, #44474f);margin-bottom:2px}:host ::ng-deep .praxis-dynamic-form--compact-presentation .praxis-presentation__value,:host ::ng-deep .form-section--compact-presentation .praxis-presentation__value,:host ::ng-deep [data-presentation-preset=compact-presentation] .praxis-presentation__value{font-size:.88rem;font-weight:500;color:var(--md-sys-color-on-surface, #1a1c1e);line-height:1.35}:host-context(.mdc-theme-dark) .praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section.form-section--corporate-dossier:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier]:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form.praxis-dynamic-form--corporate-dossier .form-section:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section.form-section--corporate-dossier:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=corporate-dossier]:not(.section-appearance-plain){background:var(--md-sys-color-surface-container-low);border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);box-shadow:0 2px 8px #0000004d}:host-context(.mdc-theme-dark) .praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section.form-section--editorial-card:not(.section-appearance-plain),:host-context(.mdc-theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=editorial-card]:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form.praxis-dynamic-form--editorial-card .form-section:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section.form-section--editorial-card:not(.section-appearance-plain),:host-context(.theme-dark) .praxis-dynamic-form .form-section[data-presentation-preset=editorial-card]:not(.section-appearance-plain){background:var(--pfx-editorial-form-surface, var(--md-sys-color-surface-container-low));border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);box-shadow:0 4px 16px #0006}.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-width:0;border-radius:0;padding:0;background:transparent;box-shadow:none}.praxis-dynamic-form .form-section.section-appearance-plain.section-has-divider{padding-bottom:16px;border-bottom:1px solid var(--pfx-form-section-divider, var(--md-sys-color-outline-variant, #e0e2ec))}.praxis-dynamic-form .section-drop-wrapper:last-of-type>.form-section.section-appearance-plain.section-has-divider,.praxis-dynamic-form>.form-section.section-appearance-plain.section-has-divider:last-of-type{border-bottom:none;padding-bottom:0}.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, 0);place-items:center;padding:var(--pdx-form-context-empty-padding, 0)}.form-context-empty-state praxis-empty-state-card{display:block;width:min(100%,var(--pdx-form-context-empty-max-width, 32rem))}.prx-form-tabs{display:block;margin-bottom:16px;max-width:100%}.prx-form-tabs__tablist{display:flex;flex-wrap:wrap;align-items:center;gap:8px;max-width:100%}.prx-form-tabs__tablist--scrollable{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding:4px 2px}.prx-form-tabs__tablist--scrollable::-webkit-scrollbar{display:none}.prx-form-tabs__tab{display:inline-flex;align-items:center;gap:8px;min-width:0;padding:8px 14px;border-radius:999px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .12));background:color-mix(in srgb,var(--md-sys-color-surface, transparent) 40%,transparent);color:var(--md-sys-color-on-surface, #1d1b20);font-family:inherit;font-size:.84rem;font-weight:500;cursor:pointer;white-space:nowrap;flex-shrink:0;-webkit-user-select:none;user-select:none;transition:all .2s cubic-bezier(.2,0,0,1)}.prx-form-tabs__tab:hover:not(:disabled):not(.prx-form-tabs__tab--active){background:var(--md-sys-color-surface-container-high, rgba(0, 0, 0, .05));border-color:var(--md-sys-color-outline, rgba(0, 0, 0, .24));color:var(--md-sys-color-on-surface)}.prx-form-tabs__tab:focus-visible{outline:2px solid var(--md-sys-color-primary, #005ac1);outline-offset:2px}.prx-form-tabs__tab:disabled{cursor:not-allowed;opacity:.45}.prx-form-tabs__tab--active{background:var(--md-sys-color-primary-container, color-mix(in srgb, var(--md-sys-color-primary, #005ac1) 16%, var(--md-sys-color-surface-container-high, #2b2930)));color:var(--md-sys-color-on-primary-container, var(--md-sys-color-primary, #005ac1));border-color:transparent;font-weight:600;box-shadow:0 1px 3px #00000014}.prx-form-tabs__tab-icon{font-size:18px;width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center}.prx-form-tabs__tab-badge{display:inline-flex;align-items:center;justify-content:center;padding:1px 7px;font-size:.72rem;font-weight:600;border-radius:999px;background:color-mix(in srgb,currentColor 14%,transparent)}.prx-form-tabs__tab-error-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;font-size:.7rem;font-weight:700;background:var(--md-sys-color-error, #ba1a1a);color:var(--md-sys-color-on-error, #ffffff);box-shadow:0 1px 2px #0003}.prx-form-tabs[data-appearance=underline]{border-bottom:1px solid var(--md-sys-color-outline-variant, #cac4d0)}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tablist{gap:16px;padding-bottom:0}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tab{border:none;border-radius:0;border-bottom:2px solid transparent;background:transparent;padding:8px 4px 10px;margin-bottom:-1px}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tab:hover:not(:disabled):not(.prx-form-tabs__tab--active){background:transparent;border-bottom-color:var(--md-sys-color-outline-variant, #cac4d0)}.prx-form-tabs[data-appearance=underline] .prx-form-tabs__tab--active{background:transparent;box-shadow:none;border-bottom-color:var(--md-sys-color-primary, #005ac1);color:var(--md-sys-color-primary, #005ac1)}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tablist{background:var(--md-sys-color-surface-container, rgba(0, 0, 0, .04));border-radius:12px;padding:4px;gap:4px;border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tab{border:none;border-radius:8px;padding:6px 12px;background:transparent}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tab:hover:not(:disabled):not(.prx-form-tabs__tab--active){background:color-mix(in srgb,currentColor 8%,transparent)}.prx-form-tabs[data-appearance=buttons] .prx-form-tabs__tab--active{background:var(--md-sys-color-surface, #ffffff);color:var(--md-sys-color-primary, #005ac1);box-shadow:0 1px 3px #0000001f}.section-drop-wrapper[hidden]{display:none!important}\n"] }]
20988
21654
  }], 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: [{
20989
21655
  type: Inject,
20990
21656
  args: [ASYNC_CONFIG_STORAGE]
@@ -21068,6 +21734,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21068
21734
  type: Input
21069
21735
  }], layout: [{
21070
21736
  type: Input
21737
+ }], layoutMode: [{
21738
+ type: Input
21739
+ }], formLayout: [{
21740
+ type: Input
21071
21741
  }], generatedLayoutPreset: [{
21072
21742
  type: Input
21073
21743
  }], layoutPolicy: [{
@@ -21096,6 +21766,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21096
21766
  type: Input
21097
21767
  }], presentation: [{
21098
21768
  type: Input
21769
+ }], presentationPreset: [{
21770
+ type: Input
21771
+ }], sectionDefaultAppearance: [{
21772
+ type: Input
21773
+ }], sectionDivider: [{
21774
+ type: Input
21099
21775
  }], visibleGlobal: [{
21100
21776
  type: Input
21101
21777
  }], fieldIconPolicy: [{
@@ -21142,6 +21818,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
21142
21818
  type: Output
21143
21819
  }], reactiveDeterminationPendingChange: [{
21144
21820
  type: Output
21821
+ }], tabChange: [{
21822
+ type: Output
21823
+ }], tabSelected: [{
21824
+ type: Output
21145
21825
  }], formHost: [{
21146
21826
  type: ViewChild,
21147
21827
  args: ['formHost', { static: false }]
@@ -30863,7 +31543,8 @@ class PraxisDynamicFormConfigEditor {
30863
31543
  this.updateDirtyState('display-mode-change');
30864
31544
  }
30865
31545
  get displayModeHint() {
30866
- if (this.inputMode !== 'view')
31546
+ const isViewLike = this.inputMode === 'view' || this.inputMode === 'presentation' || this.inputMode === 'dossier';
31547
+ if (!isViewLike)
30867
31548
  return this.inputPresentationMode === true
30868
31549
  ? 'config.general.displayMode.pendingHint' : 'config.general.displayMode.entryHint';
30869
31550
  return this.inputPresentationMode === true ? 'config.general.displayMode.viewHint'
@@ -32537,7 +33218,7 @@ class PraxisDynamicFormConfigEditor {
32537
33218
  this.cdr.detectChanges();
32538
33219
  }
32539
33220
  normalizeMode(value) {
32540
- if (value === 'edit' || value === 'view' || value === 'create')
33221
+ if (value === 'edit' || value === 'view' || value === 'create' || value === 'presentation' || value === 'dossier')
32541
33222
  return value;
32542
33223
  return 'create';
32543
33224
  }
@@ -32648,7 +33329,7 @@ class PraxisDynamicFormConfigEditor {
32648
33329
  return Object.entries(params).reduce((text, [key, value]) => text.split(`{{${key}}}`).join(String(value)), fallback);
32649
33330
  }
32650
33331
  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 });
32651
- 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 [preserveContent]=\"true\" 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 (supportsPresentationSettings) {\n <mat-card class=\"section-card\" data-testid=\"form-empty-state-settings\">\n <mat-card-content>\n <h3>{{ tx('config.emptyState.heading') }}</h3>\n <p class=\"text-caption\">{{ tx('config.emptyState.help') }}</p>\n <mat-slide-toggle [ngModel]=\"!!inputEmptyState\" (ngModelChange)=\"setEmptyStateEnabled($event)\">{{ tx('config.emptyState.enabled') }}</mat-slide-toggle>\n @if (inputMode !== 'view') { <p class=\"text-caption\">{{ tx('config.emptyState.viewOnly') }}</p> }\n @if (inputEmptyState; as empty) {\n <div class=\"empty-state-fields empty-state-content\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.title') }}</mat-label><input matInput required [(ngModel)]=\"empty.title\" (ngModelChange)=\"onEmptyStateChange()\" /><mat-hint *ngIf=\"!empty.title?.trim()\">{{ tx('config.emptyState.titleRequired') }}</mat-hint></mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('config.emptyState.icon') }}</mat-label>\n @if (empty.icon) { <mat-icon matPrefix [praxisIcon]=\"empty.icon\" aria-hidden=\"true\"></mat-icon> }\n <input matInput [(ngModel)]=\"empty.icon\" (ngModelChange)=\"onEmptyStateChange()\" />\n <span matSuffix class=\"empty-state-icon-actions\">\n <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.pickIcon')\" (click)=\"pickEmptyStateIcon()\"><mat-icon aria-hidden=\"true\">search</mat-icon></button>\n @if (empty.icon) { <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.clearIcon')\" (click)=\"empty.icon = ''; onEmptyStateChange()\"><mat-icon aria-hidden=\"true\">close</mat-icon></button> }\n </span>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"empty-state-description\"><mat-label>{{ tx('config.emptyState.description') }}</mat-label><textarea matInput rows=\"2\" [(ngModel)]=\"empty.description\" (ngModelChange)=\"onEmptyStateChange()\"></textarea></mat-form-field>\n </div>\n <details class=\"empty-state-appearance\"><summary>{{ tx('config.emptyState.appearance') }}</summary><div class=\"empty-state-fields\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.tone') }}</mat-label><mat-select [(ngModel)]=\"empty.tone\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.tone; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.variant') }}</mat-label><mat-select [(ngModel)]=\"empty.variant\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.variant; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.alignment') }}</mat-label><mat-select [(ngModel)]=\"empty.alignment\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.alignment; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.density') }}</mat-label><mat-select [(ngModel)]=\"empty.density\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.density; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.iconContainer') }}</mat-label><mat-select [(ngModel)]=\"empty.iconContainer\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.iconContainer; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n </div></details>\n }\n </mat-card-content>\n </mat-card>\n }\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 #actionsDraft [config]=\"editedConfig\" (validationChange)=\"onSurfaceDraftValidity(actionsDraft, $event)\" (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 [disabled]=\"hasInvalidSurfaceDraft\" [(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\" [disabled]=\"hasInvalidSurfaceDraft\" (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]=\"hasInvalidSurfaceDraft || !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 [disabled]=\"hasInvalidSurfaceDraft\" [(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 #commandSurfaceDraft\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 (validationChange)=\"onSurfaceDraftValidity(commandSurfaceDraft, $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{container:praxis-authoring-editor/inline-size;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)}@container praxis-authoring-editor (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}}.empty-state-fields{display:grid;align-items:start;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--p-space-3, 12px);margin-block-start:var(--p-space-4, 16px)}.empty-state-appearance summary{cursor:pointer;padding-block:var(--p-space-3, 12px);color:var(--md-sys-color-on-surface)}.empty-state-content{grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}.empty-state-description{grid-column:1/-1}.empty-state-content mat-form-field{min-width:0}.empty-state-icon-actions{display:inline-flex;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.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: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4$1.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i4$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5$1.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: i5$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$2.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { 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", "validationChange"] }, { 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", "validationChange"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }] });
33332
+ 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 [preserveContent]=\"true\" 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' && inputMode !== 'presentation' && inputMode !== 'dossier' && 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 (supportsPresentationSettings) {\n <mat-card class=\"section-card\" data-testid=\"form-empty-state-settings\">\n <mat-card-content>\n <h3>{{ tx('config.emptyState.heading') }}</h3>\n <p class=\"text-caption\">{{ tx('config.emptyState.help') }}</p>\n <mat-slide-toggle [ngModel]=\"!!inputEmptyState\" (ngModelChange)=\"setEmptyStateEnabled($event)\">{{ tx('config.emptyState.enabled') }}</mat-slide-toggle>\n @if (inputMode !== 'view' && inputMode !== 'presentation' && inputMode !== 'dossier') { <p class=\"text-caption\">{{ tx('config.emptyState.viewOnly') }}</p> }\n @if (inputEmptyState; as empty) {\n <div class=\"empty-state-fields empty-state-content\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.title') }}</mat-label><input matInput required [(ngModel)]=\"empty.title\" (ngModelChange)=\"onEmptyStateChange()\" /><mat-hint *ngIf=\"!empty.title?.trim()\">{{ tx('config.emptyState.titleRequired') }}</mat-hint></mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('config.emptyState.icon') }}</mat-label>\n @if (empty.icon) { <mat-icon matPrefix [praxisIcon]=\"empty.icon\" aria-hidden=\"true\"></mat-icon> }\n <input matInput [(ngModel)]=\"empty.icon\" (ngModelChange)=\"onEmptyStateChange()\" />\n <span matSuffix class=\"empty-state-icon-actions\">\n <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.pickIcon')\" (click)=\"pickEmptyStateIcon()\"><mat-icon aria-hidden=\"true\">search</mat-icon></button>\n @if (empty.icon) { <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.clearIcon')\" (click)=\"empty.icon = ''; onEmptyStateChange()\"><mat-icon aria-hidden=\"true\">close</mat-icon></button> }\n </span>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"empty-state-description\"><mat-label>{{ tx('config.emptyState.description') }}</mat-label><textarea matInput rows=\"2\" [(ngModel)]=\"empty.description\" (ngModelChange)=\"onEmptyStateChange()\"></textarea></mat-form-field>\n </div>\n <details class=\"empty-state-appearance\"><summary>{{ tx('config.emptyState.appearance') }}</summary><div class=\"empty-state-fields\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.tone') }}</mat-label><mat-select [(ngModel)]=\"empty.tone\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.tone; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.variant') }}</mat-label><mat-select [(ngModel)]=\"empty.variant\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.variant; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.alignment') }}</mat-label><mat-select [(ngModel)]=\"empty.alignment\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.alignment; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.density') }}</mat-label><mat-select [(ngModel)]=\"empty.density\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.density; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.iconContainer') }}</mat-label><mat-select [(ngModel)]=\"empty.iconContainer\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.iconContainer; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n </div></details>\n }\n </mat-card-content>\n </mat-card>\n }\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 #actionsDraft [config]=\"editedConfig\" (validationChange)=\"onSurfaceDraftValidity(actionsDraft, $event)\" (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 [disabled]=\"hasInvalidSurfaceDraft\" [(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\" [disabled]=\"hasInvalidSurfaceDraft\" (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]=\"hasInvalidSurfaceDraft || !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 [disabled]=\"hasInvalidSurfaceDraft\" [(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 #commandSurfaceDraft\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 (validationChange)=\"onSurfaceDraftValidity(commandSurfaceDraft, $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{container:praxis-authoring-editor/inline-size;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)}@container praxis-authoring-editor (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}}.empty-state-fields{display:grid;align-items:start;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--p-space-3, 12px);margin-block-start:var(--p-space-4, 16px)}.empty-state-appearance summary{cursor:pointer;padding-block:var(--p-space-3, 12px);color:var(--md-sys-color-on-surface)}.empty-state-content{grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}.empty-state-description{grid-column:1/-1}.empty-state-content mat-form-field{min-width:0}.empty-state-icon-actions{display:inline-flex;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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$2.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i6$2.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: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4$1.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i4$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5$1.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: i5$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4$2.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { 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", "validationChange"] }, { 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", "validationChange"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }] });
32652
33333
  }
32653
33334
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisDynamicFormConfigEditor, decorators: [{
32654
33335
  type: Component,
@@ -32678,7 +33359,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32678
33359
  PraxisVisualBuilder,
32679
33360
  CascadeManagerTabComponent,
32680
33361
  SurfaceOpenActionEditorComponent,
32681
- ], 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 [preserveContent]=\"true\" 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 (supportsPresentationSettings) {\n <mat-card class=\"section-card\" data-testid=\"form-empty-state-settings\">\n <mat-card-content>\n <h3>{{ tx('config.emptyState.heading') }}</h3>\n <p class=\"text-caption\">{{ tx('config.emptyState.help') }}</p>\n <mat-slide-toggle [ngModel]=\"!!inputEmptyState\" (ngModelChange)=\"setEmptyStateEnabled($event)\">{{ tx('config.emptyState.enabled') }}</mat-slide-toggle>\n @if (inputMode !== 'view') { <p class=\"text-caption\">{{ tx('config.emptyState.viewOnly') }}</p> }\n @if (inputEmptyState; as empty) {\n <div class=\"empty-state-fields empty-state-content\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.title') }}</mat-label><input matInput required [(ngModel)]=\"empty.title\" (ngModelChange)=\"onEmptyStateChange()\" /><mat-hint *ngIf=\"!empty.title?.trim()\">{{ tx('config.emptyState.titleRequired') }}</mat-hint></mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('config.emptyState.icon') }}</mat-label>\n @if (empty.icon) { <mat-icon matPrefix [praxisIcon]=\"empty.icon\" aria-hidden=\"true\"></mat-icon> }\n <input matInput [(ngModel)]=\"empty.icon\" (ngModelChange)=\"onEmptyStateChange()\" />\n <span matSuffix class=\"empty-state-icon-actions\">\n <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.pickIcon')\" (click)=\"pickEmptyStateIcon()\"><mat-icon aria-hidden=\"true\">search</mat-icon></button>\n @if (empty.icon) { <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.clearIcon')\" (click)=\"empty.icon = ''; onEmptyStateChange()\"><mat-icon aria-hidden=\"true\">close</mat-icon></button> }\n </span>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"empty-state-description\"><mat-label>{{ tx('config.emptyState.description') }}</mat-label><textarea matInput rows=\"2\" [(ngModel)]=\"empty.description\" (ngModelChange)=\"onEmptyStateChange()\"></textarea></mat-form-field>\n </div>\n <details class=\"empty-state-appearance\"><summary>{{ tx('config.emptyState.appearance') }}</summary><div class=\"empty-state-fields\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.tone') }}</mat-label><mat-select [(ngModel)]=\"empty.tone\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.tone; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.variant') }}</mat-label><mat-select [(ngModel)]=\"empty.variant\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.variant; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.alignment') }}</mat-label><mat-select [(ngModel)]=\"empty.alignment\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.alignment; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.density') }}</mat-label><mat-select [(ngModel)]=\"empty.density\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.density; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.iconContainer') }}</mat-label><mat-select [(ngModel)]=\"empty.iconContainer\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.iconContainer; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n </div></details>\n }\n </mat-card-content>\n </mat-card>\n }\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 #actionsDraft [config]=\"editedConfig\" (validationChange)=\"onSurfaceDraftValidity(actionsDraft, $event)\" (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 [disabled]=\"hasInvalidSurfaceDraft\" [(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\" [disabled]=\"hasInvalidSurfaceDraft\" (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]=\"hasInvalidSurfaceDraft || !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 [disabled]=\"hasInvalidSurfaceDraft\" [(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 #commandSurfaceDraft\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 (validationChange)=\"onSurfaceDraftValidity(commandSurfaceDraft, $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{container:praxis-authoring-editor/inline-size;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)}@container praxis-authoring-editor (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}}.empty-state-fields{display:grid;align-items:start;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--p-space-3, 12px);margin-block-start:var(--p-space-4, 16px)}.empty-state-appearance summary{cursor:pointer;padding-block:var(--p-space-3, 12px);color:var(--md-sys-color-on-surface)}.empty-state-content{grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}.empty-state-description{grid-column:1/-1}.empty-state-content mat-form-field{min-width:0}.empty-state-icon-actions{display:inline-flex;align-items:center}\n"] }]
33362
+ ], 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 [preserveContent]=\"true\" 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' && inputMode !== 'presentation' && inputMode !== 'dossier' && 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 (supportsPresentationSettings) {\n <mat-card class=\"section-card\" data-testid=\"form-empty-state-settings\">\n <mat-card-content>\n <h3>{{ tx('config.emptyState.heading') }}</h3>\n <p class=\"text-caption\">{{ tx('config.emptyState.help') }}</p>\n <mat-slide-toggle [ngModel]=\"!!inputEmptyState\" (ngModelChange)=\"setEmptyStateEnabled($event)\">{{ tx('config.emptyState.enabled') }}</mat-slide-toggle>\n @if (inputMode !== 'view' && inputMode !== 'presentation' && inputMode !== 'dossier') { <p class=\"text-caption\">{{ tx('config.emptyState.viewOnly') }}</p> }\n @if (inputEmptyState; as empty) {\n <div class=\"empty-state-fields empty-state-content\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.title') }}</mat-label><input matInput required [(ngModel)]=\"empty.title\" (ngModelChange)=\"onEmptyStateChange()\" /><mat-hint *ngIf=\"!empty.title?.trim()\">{{ tx('config.emptyState.titleRequired') }}</mat-hint></mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('config.emptyState.icon') }}</mat-label>\n @if (empty.icon) { <mat-icon matPrefix [praxisIcon]=\"empty.icon\" aria-hidden=\"true\"></mat-icon> }\n <input matInput [(ngModel)]=\"empty.icon\" (ngModelChange)=\"onEmptyStateChange()\" />\n <span matSuffix class=\"empty-state-icon-actions\">\n <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.pickIcon')\" (click)=\"pickEmptyStateIcon()\"><mat-icon aria-hidden=\"true\">search</mat-icon></button>\n @if (empty.icon) { <button mat-icon-button type=\"button\" [attr.aria-label]=\"tx('config.emptyState.clearIcon')\" (click)=\"empty.icon = ''; onEmptyStateChange()\"><mat-icon aria-hidden=\"true\">close</mat-icon></button> }\n </span>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"empty-state-description\"><mat-label>{{ tx('config.emptyState.description') }}</mat-label><textarea matInput rows=\"2\" [(ngModel)]=\"empty.description\" (ngModelChange)=\"onEmptyStateChange()\"></textarea></mat-form-field>\n </div>\n <details class=\"empty-state-appearance\"><summary>{{ tx('config.emptyState.appearance') }}</summary><div class=\"empty-state-fields\">\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.tone') }}</mat-label><mat-select [(ngModel)]=\"empty.tone\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.tone; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.variant') }}</mat-label><mat-select [(ngModel)]=\"empty.variant\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.variant; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.alignment') }}</mat-label><mat-select [(ngModel)]=\"empty.alignment\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.alignment; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.density') }}</mat-label><mat-select [(ngModel)]=\"empty.density\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.density; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n <mat-form-field appearance=\"outline\"><mat-label>{{ tx('config.emptyState.iconContainer') }}</mat-label><mat-select [(ngModel)]=\"empty.iconContainer\" (ngModelChange)=\"onEmptyStateChange()\"><mat-option [value]=\"undefined\">{{ tx('config.emptyState.inherit') }}</mat-option>@for (value of emptyStateOptions.iconContainer; track value) { <mat-option [value]=\"value\">{{ tx('config.emptyState.option.' + value) }}</mat-option> }</mat-select></mat-form-field>\n </div></details>\n }\n </mat-card-content>\n </mat-card>\n }\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 #actionsDraft [config]=\"editedConfig\" (validationChange)=\"onSurfaceDraftValidity(actionsDraft, $event)\" (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 [disabled]=\"hasInvalidSurfaceDraft\" [(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\" [disabled]=\"hasInvalidSurfaceDraft\" (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]=\"hasInvalidSurfaceDraft || !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 [disabled]=\"hasInvalidSurfaceDraft\" [(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 #commandSurfaceDraft\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 (validationChange)=\"onSurfaceDraftValidity(commandSurfaceDraft, $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{container:praxis-authoring-editor/inline-size;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)}@container praxis-authoring-editor (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}}.empty-state-fields{display:grid;align-items:start;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--p-space-3, 12px);margin-block-start:var(--p-space-4, 16px)}.empty-state-appearance summary{cursor:pointer;padding-block:var(--p-space-3, 12px);color:var(--md-sys-color-on-surface)}.empty-state-content{grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}.empty-state-description{grid-column:1/-1}.empty-state-content mat-form-field{min-width:0}.empty-state-icon-actions{display:inline-flex;align-items:center}\n"] }]
32682
33363
  }], ctorParameters: () => [{ type: undefined, decorators: [{
32683
33364
  type: Inject,
32684
33365
  args: [ASYNC_CONFIG_STORAGE]
@@ -32937,103 +33618,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
32937
33618
  type: Output
32938
33619
  }] } });
32939
33620
 
32940
- class PraxisFilterFormWidgetConfigEditor {
32941
- inputs = null;
32942
- widgetKey;
32943
- formEditor;
32944
- isDirty$ = new BehaviorSubject(false);
32945
- isValid$ = new BehaviorSubject(true);
32946
- isBusy$ = new BehaviorSubject(false);
32947
- subscription = new Subscription();
32948
- ngAfterViewInit() {
32949
- if (!this.formEditor) {
32950
- return;
32951
- }
32952
- this.formEditor.supportsPresentationSettings = false;
32953
- this.initializeChildEditor();
32954
- this.subscription.add(this.formEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
32955
- this.subscription.add(this.formEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
32956
- this.subscription.add(this.formEditor.isBusy$.subscribe((value) => this.isBusy$.next(value)));
32957
- }
32958
- ngOnDestroy() {
32959
- this.subscription.unsubscribe();
32960
- }
32961
- getSettingsValue() {
32962
- return this.buildValue(this.formEditor?.getSettingsValue());
32963
- }
32964
- onSave() {
32965
- return this.buildValue(this.formEditor?.onSave?.() ?? this.formEditor?.getSettingsValue());
32966
- }
32967
- reset() {
32968
- this.formEditor?.reset?.();
32969
- }
32970
- initializeChildEditor() {
32971
- const document = this.createDocumentFromInputs();
32972
- const serialized = serializeDynamicFormAuthoringDocument(document);
32973
- const editor = this.formEditor;
32974
- editor.onJsonConfigChange?.(serialized);
32975
- editor.initialDocument = document;
32976
- editor.initialConfig = document.config;
32977
- editor.updateDirtyState?.('filter-form-widget-config-init');
32978
- editor.isDirty$?.next(false);
32979
- editor.isValid$?.next(true);
32980
- }
32981
- buildValue(rawDocument) {
32982
- const document = parseLegacyOrDynamicFormDocument(rawDocument ?? this.createDocumentFromInputs());
32983
- return {
32984
- inputs: {
32985
- ...(this.inputs ?? {}),
32986
- config: document.config,
32987
- formId: this.inputs?.formId ?? this.widgetKey,
32988
- resourcePath: this.inputs?.resourcePath,
32989
- mode: document.bindings?.mode ?? this.inputs?.mode ?? 'create',
32990
- },
32991
- };
32992
- }
32993
- createDocumentFromInputs() {
32994
- return parseLegacyOrDynamicFormDocument({
32995
- kind: 'praxis.dynamic-form.editor',
32996
- version: 1,
32997
- config: this.inputs?.config ?? { sections: [], fieldMetadata: [] },
32998
- bindings: {
32999
- mode: this.normalizeMode(this.inputs?.mode) ?? 'create',
33000
- },
33001
- });
33002
- }
33003
- normalizeMode(value) {
33004
- return value === 'create' || value === 'edit' || value === 'view'
33005
- ? value
33006
- : undefined;
33007
- }
33008
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisFilterFormWidgetConfigEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
33009
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PraxisFilterFormWidgetConfigEditor, isStandalone: true, selector: "praxis-filter-form-widget-config-editor", inputs: { inputs: "inputs", widgetKey: "widgetKey" }, viewQueries: [{ propertyName: "formEditor", first: true, predicate: ["formEditor"], descendants: true }], ngImport: i0, template: `
33010
- <section data-testid="filter-form-widget-config-editor">
33011
- <praxis-dynamic-form-config-editor #formEditor />
33012
- </section>
33013
- `, isInline: true, dependencies: [{ kind: "component", type: PraxisDynamicFormConfigEditor, selector: "praxis-dynamic-form-config-editor" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
33014
- }
33015
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisFilterFormWidgetConfigEditor, decorators: [{
33016
- type: Component,
33017
- args: [{
33018
- selector: 'praxis-filter-form-widget-config-editor',
33019
- standalone: true,
33020
- imports: [PraxisDynamicFormConfigEditor],
33021
- template: `
33022
- <section data-testid="filter-form-widget-config-editor">
33023
- <praxis-dynamic-form-config-editor #formEditor />
33024
- </section>
33025
- `,
33026
- changeDetection: ChangeDetectionStrategy.OnPush,
33027
- }]
33028
- }], propDecorators: { inputs: [{
33029
- type: Input
33030
- }], widgetKey: [{
33031
- type: Input
33032
- }], formEditor: [{
33033
- type: ViewChild,
33034
- args: ['formEditor']
33035
- }] } });
33036
-
33037
33621
  const PRAXIS_FILTER_FORM_PHASE1_PORTS = [
33038
33622
  {
33039
33623
  id: 'config',
@@ -33100,7 +33684,7 @@ const PRAXIS_FILTER_FORM_COMPONENT_METADATA = {
33100
33684
  description: 'Filter form driven by FormConfig and fieldMetadata.',
33101
33685
  icon: 'filter_alt',
33102
33686
  configEditor: {
33103
- component: PraxisFilterFormWidgetConfigEditor,
33687
+ loadComponent: async () => (await Promise.resolve().then(function () { return praxisFilterFormWidgetConfigEditor; })).PraxisFilterFormWidgetConfigEditor,
33104
33688
  title: 'Configurar filtro',
33105
33689
  },
33106
33690
  authoringManifestRef: {
@@ -33176,6 +33760,108 @@ function providePraxisFilterFormMetadata() {
33176
33760
  };
33177
33761
  }
33178
33762
 
33763
+ class PraxisFilterFormWidgetConfigEditor {
33764
+ inputs = null;
33765
+ widgetKey;
33766
+ formEditor;
33767
+ isDirty$ = new BehaviorSubject(false);
33768
+ isValid$ = new BehaviorSubject(true);
33769
+ isBusy$ = new BehaviorSubject(false);
33770
+ subscription = new Subscription();
33771
+ ngAfterViewInit() {
33772
+ if (!this.formEditor) {
33773
+ return;
33774
+ }
33775
+ this.formEditor.supportsPresentationSettings = false;
33776
+ this.initializeChildEditor();
33777
+ this.subscription.add(this.formEditor.isDirty$.subscribe((value) => this.isDirty$.next(value)));
33778
+ this.subscription.add(this.formEditor.isValid$.subscribe((value) => this.isValid$.next(value)));
33779
+ this.subscription.add(this.formEditor.isBusy$.subscribe((value) => this.isBusy$.next(value)));
33780
+ }
33781
+ ngOnDestroy() {
33782
+ this.subscription.unsubscribe();
33783
+ }
33784
+ getSettingsValue() {
33785
+ return this.buildValue(this.formEditor?.getSettingsValue());
33786
+ }
33787
+ onSave() {
33788
+ return this.buildValue(this.formEditor?.onSave?.() ?? this.formEditor?.getSettingsValue());
33789
+ }
33790
+ reset() {
33791
+ this.formEditor?.reset?.();
33792
+ }
33793
+ initializeChildEditor() {
33794
+ const document = this.createDocumentFromInputs();
33795
+ const serialized = serializeDynamicFormAuthoringDocument(document);
33796
+ const editor = this.formEditor;
33797
+ editor.onJsonConfigChange?.(serialized);
33798
+ editor.initialDocument = document;
33799
+ editor.initialConfig = document.config;
33800
+ editor.updateDirtyState?.('filter-form-widget-config-init');
33801
+ editor.isDirty$?.next(false);
33802
+ editor.isValid$?.next(true);
33803
+ }
33804
+ buildValue(rawDocument) {
33805
+ const document = parseLegacyOrDynamicFormDocument(rawDocument ?? this.createDocumentFromInputs());
33806
+ return {
33807
+ inputs: {
33808
+ ...(this.inputs ?? {}),
33809
+ config: document.config,
33810
+ formId: this.inputs?.formId ?? this.widgetKey,
33811
+ resourcePath: this.inputs?.resourcePath,
33812
+ mode: document.bindings?.mode ?? this.inputs?.mode ?? 'create',
33813
+ },
33814
+ };
33815
+ }
33816
+ createDocumentFromInputs() {
33817
+ return parseLegacyOrDynamicFormDocument({
33818
+ kind: 'praxis.dynamic-form.editor',
33819
+ version: 1,
33820
+ config: this.inputs?.config ?? { sections: [], fieldMetadata: [] },
33821
+ bindings: {
33822
+ mode: this.normalizeMode(this.inputs?.mode) ?? 'create',
33823
+ },
33824
+ });
33825
+ }
33826
+ normalizeMode(value) {
33827
+ return value === 'create' || value === 'edit' || value === 'view'
33828
+ ? value
33829
+ : undefined;
33830
+ }
33831
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisFilterFormWidgetConfigEditor, deps: [], target: i0.ɵɵFactoryTarget.Component });
33832
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PraxisFilterFormWidgetConfigEditor, isStandalone: true, selector: "praxis-filter-form-widget-config-editor", inputs: { inputs: "inputs", widgetKey: "widgetKey" }, viewQueries: [{ propertyName: "formEditor", first: true, predicate: ["formEditor"], descendants: true }], ngImport: i0, template: `
33833
+ <section data-testid="filter-form-widget-config-editor">
33834
+ <praxis-dynamic-form-config-editor #formEditor />
33835
+ </section>
33836
+ `, isInline: true, dependencies: [{ kind: "component", type: PraxisDynamicFormConfigEditor, selector: "praxis-dynamic-form-config-editor" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
33837
+ }
33838
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisFilterFormWidgetConfigEditor, decorators: [{
33839
+ type: Component,
33840
+ args: [{
33841
+ selector: 'praxis-filter-form-widget-config-editor',
33842
+ standalone: true,
33843
+ imports: [PraxisDynamicFormConfigEditor],
33844
+ template: `
33845
+ <section data-testid="filter-form-widget-config-editor">
33846
+ <praxis-dynamic-form-config-editor #formEditor />
33847
+ </section>
33848
+ `,
33849
+ changeDetection: ChangeDetectionStrategy.OnPush,
33850
+ }]
33851
+ }], propDecorators: { inputs: [{
33852
+ type: Input
33853
+ }], widgetKey: [{
33854
+ type: Input
33855
+ }], formEditor: [{
33856
+ type: ViewChild,
33857
+ args: ['formEditor']
33858
+ }] } });
33859
+
33860
+ var praxisFilterFormWidgetConfigEditor = /*#__PURE__*/Object.freeze({
33861
+ __proto__: null,
33862
+ PraxisFilterFormWidgetConfigEditor: PraxisFilterFormWidgetConfigEditor
33863
+ });
33864
+
33179
33865
  class PraxisDynamicFormWidgetConfigEditor {
33180
33866
  inputs = null;
33181
33867
  widgetKey;
@@ -33405,6 +34091,11 @@ function isRecord(value) {
33405
34091
  return value !== null && typeof value === 'object' && !Array.isArray(value);
33406
34092
  }
33407
34093
 
34094
+ var praxisDynamicFormWidgetConfigEditor = /*#__PURE__*/Object.freeze({
34095
+ __proto__: null,
34096
+ PraxisDynamicFormWidgetConfigEditor: PraxisDynamicFormWidgetConfigEditor
34097
+ });
34098
+
33408
34099
  // Owner-qualified dictionary keys work through the registry's existing editorial
33409
34100
  // resolver without requiring a consuming builder to know the form's namespace.
33410
34101
  const FORM_EDITORIAL_LABELS = {
@@ -33434,6 +34125,7 @@ const FORM_EDITORIAL_LABELS = {
33434
34125
  readonlyModeGlobal: ['Campos somente para leitura', 'Read-only fields'],
33435
34126
  disabledModeGlobal: ['Desabilitar campos', 'Disable fields'],
33436
34127
  presentation: ['Aparência do formulário', 'Form appearance'],
34128
+ presentationPreset: ['Preset visual de apresentação', 'Presentation visual preset'],
33437
34129
  fieldIconPolicy: ['Exibição dos ícones de campos', 'Field icon display'],
33438
34130
  visibleGlobal: ['Mostrar formulário', 'Show form'],
33439
34131
  customEndpoints: ['Endereços personalizados', 'Custom endpoints'],
@@ -33441,6 +34133,7 @@ const FORM_EDITORIAL_LABELS = {
33441
34133
  const FORM_EDITORIAL_HELP = {
33442
34134
  mode: ['create cria um registro; edit altera um registro; view permite consultá-lo. A apresentação dos campos é configurada separadamente.', 'create creates a record; edit changes a record; view displays it. Field presentation is configured separately.'],
33443
34135
  presentationModeGlobal: ['No modo view, Sim mostra rótulos e valores; Não mostra os campos. Usar padrão remove este ajuste; null segue a política de layout.', 'In view mode, Yes shows labels and values; No shows fields. Use default removes this override; null follows the layout policy.'],
34136
+ presentationPreset: ['Estilo visual nativo em modo apresentação: dossiê corporativo, card editorial, apresentação compacta ou padrão.', 'Native visual style in presentation mode: corporate dossier, editorial card, compact presentation, or default.'],
33444
34137
  configPersistenceStrategy: ['input-first prioriza a configuração enviada ao abrir esta ficha. local-first prioriza as preferências salvas do formulário.', 'input-first prioritizes the configuration supplied when opening this form. local-first prioritizes saved form preferences.'],
33445
34138
  resourceId: ['Identificador do registro consultado. Pode receber o registro selecionado por um vínculo.', 'Identity of the record to read. It can receive the selected record through a binding.'],
33446
34139
  formId: ['Chave estável usada para identificar e salvar as preferências deste formulário.', 'Stable key used to identify and save this form’s preferences.'],
@@ -33673,7 +34366,7 @@ const PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA = {
33673
34366
  source: 'PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST',
33674
34367
  },
33675
34368
  configEditor: {
33676
- component: PraxisDynamicFormWidgetConfigEditor,
34369
+ loadComponent: async () => (await Promise.resolve().then(function () { return praxisDynamicFormWidgetConfigEditor; })).PraxisDynamicFormWidgetConfigEditor,
33677
34370
  contextResolver: ({ materializedInputs }) => ({
33678
34371
  context: {
33679
34372
  effectiveConfig: materializedInputs?.['config'],
@@ -33728,6 +34421,7 @@ const PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA = {
33728
34421
  { name: 'readonlyModeGlobal', type: 'boolean | null', description: 'Trava global para campos em modo somente-leitura' },
33729
34422
  { name: 'disabledModeGlobal', type: 'boolean | null', description: 'Trava global para desabilitar campos' },
33730
34423
  { 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.' },
34424
+ { name: 'presentationPreset', type: 'FormPresentationPreset', label: 'Preset de Apresentação', description: 'Preset visual nativo para modo apresentação: corporate-dossier, editorial-card, compact-presentation ou default.' },
33731
34425
  { 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.' },
33732
34426
  { 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.' },
33733
34427
  { name: 'visibleGlobal', type: 'boolean | null', description: 'Visibilidade global' },
@@ -33853,6 +34547,46 @@ function providePraxisDynamicFormMetadata() {
33853
34547
  }];
33854
34548
  }
33855
34549
 
34550
+ /**
34551
+ * DynamicFormSchemaCacheService
34552
+ * ------------------------------
34553
+ * Serviço canônico de conveniência em `@praxisui/dynamic-form` para orquestração
34554
+ * de cache de primeiro nível (L1) de esquemas OpenAPI compilados (Issue #2).
34555
+ *
34556
+ * Delega o ciclo de vida do cache em memória ao DynamicFormService (@praxisui/core),
34557
+ * garantindo consistência referencial entre módulos e transições de abas em 0ms.
34558
+ */
34559
+ class DynamicFormSchemaCacheService {
34560
+ dynamicFormService = inject(DynamicFormService);
34561
+ buildCacheKey(params) {
34562
+ return this.dynamicFormService.buildSchemaCacheKey(params);
34563
+ }
34564
+ get(cacheKey) {
34565
+ return this.dynamicFormService.getCompiledSchema(cacheKey);
34566
+ }
34567
+ set(cacheKey, compiled, customTtlMs) {
34568
+ this.dynamicFormService.setCompiledSchema(cacheKey, compiled, customTtlMs);
34569
+ }
34570
+ has(cacheKey) {
34571
+ return this.dynamicFormService.hasCompiledSchema(cacheKey);
34572
+ }
34573
+ invalidate(cacheKey) {
34574
+ this.dynamicFormService.invalidateCompiledSchema(cacheKey);
34575
+ }
34576
+ clear() {
34577
+ this.dynamicFormService.clearCompiledSchemaCache();
34578
+ }
34579
+ size() {
34580
+ return this.dynamicFormService.getCompiledSchemaCacheSize();
34581
+ }
34582
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormSchemaCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
34583
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormSchemaCacheService, providedIn: 'root' });
34584
+ }
34585
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: DynamicFormSchemaCacheService, decorators: [{
34586
+ type: Injectable,
34587
+ args: [{ providedIn: 'root' }]
34588
+ }] });
34589
+
33856
34590
  const ERGADM00034_COMPACT_PRESENTATION_EXAMPLE = {
33857
34591
  id: 'ergadm00034-compact-presentation',
33858
34592
  title: 'ERGadm00034: códigos de frequência',
@@ -34439,7 +35173,7 @@ class Ergadm00034CompactPresentationExampleComponent {
34439
35173
  corporatePresentationConfig = buildCorporatePresentationFormatGalleryConfig(this.dynamicLayout);
34440
35174
  corporatePresentationInitialValue = this.corporatePresentationExample.initialValue;
34441
35175
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: Ergadm00034CompactPresentationExampleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
34442
- 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 });
35176
+ 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", "layoutMode", "formLayout", "generatedLayoutPreset", "layoutPolicy", "backConfig", "hooks", "removeEmptyContainersOnSave", "reactiveValidation", "reactiveValidationDebounceMs", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "readonlyModeGlobal", "disabledModeGlobal", "presentationModeGlobal", "presentation", "presentationPreset", "sectionDefaultAppearance", "sectionDivider", "visibleGlobal", "fieldIconPolicy", "domainRules", "customEndpoints"], outputs: ["formSubmit", "formCancel", "formReset", "configChange", "configPatchChange", "formReady", "valueChange", "payloadPreviewChange", "syncCompleted", "initializationError", "loadingStateChange", "enableCustomizationChange", "customAction", "actionConfirmation", "schemaStatusChange", "fieldRenderError", "ruleDiagnosticsChange", "reactiveDeterminationExecuted", "reactiveDeterminationPendingChange", "tabChange", "tabSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
34443
35177
  }
34444
35178
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: Ergadm00034CompactPresentationExampleComponent, decorators: [{
34445
35179
  type: Component,
@@ -38598,4 +39332,4 @@ const PRAXIS_FILTER_FORM_AUTHORING_MANIFEST = projectComponentAuthoringManifest(
38598
39332
  * Generated bundle index. Do not edit.
38599
39333
  */
38600
39334
 
38601
- export { ActionsEditorComponent, CORPORATE_PRESENTATION_FORMAT_GALLERY, CanvasStateService, CanvasToolbarComponent, ColumnEditorComponent, DomainRuleFormRulesService, DynamicFormLayoutService, ERGADM00034_COMPACT_PRESENTATION_EXAMPLE, Ergadm00034CompactPresentationExampleComponent, FORM_AI_CAPABILITIES, FORM_COMPONENT_AI_CAPABILITIES, FieldConfiguratorComponent, FieldEditorComponent, FormConfigService, FormContextService, FormLayoutService, FormRulesService, JsonConfigEditorComponent, LayoutColorToken, LayoutEditorComponent, LayoutPrefsService, PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST, PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA, PRAXIS_FILTER_FORM_AUTHORING_MANIFEST, PRAXIS_FILTER_FORM_AUTHORING_PROJECTION, PRAXIS_FILTER_FORM_COMPONENT_METADATA, PraxisDynamicForm, PraxisDynamicFormConfigEditor, PraxisDynamicFormWidgetConfigEditor, PraxisFilterForm, PraxisFilterFormWidgetConfigEditor, PraxisFormActionsComponent, RowConfiguratorComponent, RowEditorComponent, SETTINGS_PANEL_DYNAMIC_FORM_PROVIDER, SectionEditorComponent, TASK_PRESETS, applyVisibilityRules, buildCorporatePresentationFormatGalleryConfig, buildDynamicFormApplyPlan, buildDynamicFormRuleAuthoringContext, buildErgadm00034CompactPresentationConfig, createDynamicFormAuthoringDocument, formLayoutRulesToBuilderState, getFormAiCatalog, getFormCapabilities, getFormEnum, isRuleSatisfied, normalizeDateArrays, normalizeDynamicFormAuthoringDocument, parseLegacyOrDynamicFormDocument, providePraxisDynamicFormMetadata, providePraxisFilterFormMetadata, provideSettingsPanelDynamicForm, ruleBuilderStateToFormLayoutRules, serializeDynamicFormAuthoringDocument, stripLegacyFieldMetadata, toCanonicalDynamicFormConfig, validateDynamicFormAuthoringDocument, validateDynamicFormAuthoringInput };
39335
+ export { ActionsEditorComponent, CORPORATE_PRESENTATION_FORMAT_GALLERY, CanvasStateService, CanvasToolbarComponent, ColumnEditorComponent, DomainRuleFormRulesService, DynamicFormLayoutService, DynamicFormSchemaCacheService, ERGADM00034_COMPACT_PRESENTATION_EXAMPLE, Ergadm00034CompactPresentationExampleComponent, FORM_AI_CAPABILITIES, FORM_COMPONENT_AI_CAPABILITIES, FieldConfiguratorComponent, FieldEditorComponent, FormConfigService, FormContextService, FormLayoutService, FormRulesService, JsonConfigEditorComponent, LayoutColorToken, LayoutEditorComponent, LayoutPrefsService, PRAXIS_DYNAMIC_FORM_AUTHORING_MANIFEST, PRAXIS_DYNAMIC_FORM_COMPONENT_METADATA, PRAXIS_FILTER_FORM_AUTHORING_MANIFEST, PRAXIS_FILTER_FORM_AUTHORING_PROJECTION, PRAXIS_FILTER_FORM_COMPONENT_METADATA, PraxisDynamicForm, PraxisDynamicFormConfigEditor, PraxisDynamicFormWidgetConfigEditor, PraxisFilterForm, PraxisFilterFormWidgetConfigEditor, PraxisFormActionsComponent, RowConfiguratorComponent, RowEditorComponent, SETTINGS_PANEL_DYNAMIC_FORM_PROVIDER, SectionEditorComponent, TASK_PRESETS, applyVisibilityRules, buildCorporatePresentationFormatGalleryConfig, buildDynamicFormApplyPlan, buildDynamicFormRuleAuthoringContext, buildErgadm00034CompactPresentationConfig, createDynamicFormAuthoringDocument, formLayoutRulesToBuilderState, getFormAiCatalog, getFormCapabilities, getFormEnum, isRuleSatisfied, normalizeDateArrays, normalizeDynamicFormAuthoringDocument, parseLegacyOrDynamicFormDocument, providePraxisDynamicFormMetadata, providePraxisFilterFormMetadata, provideSettingsPanelDynamicForm, ruleBuilderStateToFormLayoutRules, serializeDynamicFormAuthoringDocument, stripLegacyFieldMetadata, toCanonicalDynamicFormConfig, validateDynamicFormAuthoringDocument, validateDynamicFormAuthoringInput };