jupiter-dynamic-forms 1.19.6 → 1.19.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1662,6 +1662,7 @@ const form$1 = {
1662
1662
  collapsePanel: "Collapse side panel",
1663
1663
  validate: "Validate",
1664
1664
  preview: "Preview",
1665
+ download: "Download",
1665
1666
  cancelValidation: "Cancel Validation",
1666
1667
  lastValidationResults: "Last Validation Results",
1667
1668
  validationInProgress: "Validation In Progress"
@@ -1804,6 +1805,15 @@ const error$1 = {
1804
1805
  ok: "OK"
1805
1806
  }
1806
1807
  };
1808
+ const calculationWarning$1 = {
1809
+ title: "Calculation warning",
1810
+ summaryLine: 'Total "{{label}}" should equal {{calculated}}, but you entered {{entered}}.',
1811
+ childrenPrefix: "Children:",
1812
+ childAdded: "{{label}} = {{value}} (added)",
1813
+ childSubtracted: "{{label}} = {{value}} (subtracted, opposite balance)",
1814
+ added: "Added",
1815
+ subtracted: "Subtracted (opposite balance)"
1816
+ };
1807
1817
  const enTranslations = {
1808
1818
  conceptInfo: conceptInfo$1,
1809
1819
  form: form$1,
@@ -1814,7 +1824,8 @@ const enTranslations = {
1814
1824
  admin: admin$1,
1815
1825
  validation: validation$1,
1816
1826
  xbrlValidation: xbrlValidation$1,
1817
- error: error$1
1827
+ error: error$1,
1828
+ calculationWarning: calculationWarning$1
1818
1829
  };
1819
1830
  const conceptInfo = {
1820
1831
  title: "Conceptinformatie",
@@ -1846,6 +1857,7 @@ const form = {
1846
1857
  collapsePanel: "Zijpaneel inklappen",
1847
1858
  validate: "Valideren",
1848
1859
  preview: "Voorbeeld",
1860
+ download: "Downloaden",
1849
1861
  cancelValidation: "Validatie annuleren",
1850
1862
  lastValidationResults: "Laatste validatieresultaten",
1851
1863
  validationInProgress: "Validatie bezig"
@@ -1988,6 +2000,15 @@ const error = {
1988
2000
  ok: "OK"
1989
2001
  }
1990
2002
  };
2003
+ const calculationWarning = {
2004
+ title: "Berekeningswaarschuwing",
2005
+ summaryLine: 'Totaal "{{label}}" zou {{calculated}} moeten zijn, maar u heeft {{entered}} ingevoerd.',
2006
+ childrenPrefix: "Onderdelen:",
2007
+ childAdded: "{{label}} = {{value}} (opgeteld)",
2008
+ childSubtracted: "{{label}} = {{value}} (afgetrokken, tegengestelde balans)",
2009
+ added: "Opgeteld",
2010
+ subtracted: "Afgetrokken (tegengestelde balans)"
2011
+ };
1991
2012
  const nlTranslations = {
1992
2013
  conceptInfo,
1993
2014
  form,
@@ -1998,7 +2019,8 @@ const nlTranslations = {
1998
2019
  admin,
1999
2020
  validation,
2000
2021
  xbrlValidation,
2001
- error
2022
+ error,
2023
+ calculationWarning
2002
2024
  };
2003
2025
  const translations = {
2004
2026
  en: enTranslations,
@@ -4934,6 +4956,79 @@ let JupiterConceptTree = class extends LitElement {
4934
4956
  dialog.addEventListener("close", () => document.body.removeChild(dialog));
4935
4957
  dialog.showModal();
4936
4958
  }
4959
+ _ensureCalcWarningDialogStyles() {
4960
+ if (document.getElementById("jdf-calc-warning-dialog-styles"))
4961
+ return;
4962
+ const style = document.createElement("style");
4963
+ style.id = "jdf-calc-warning-dialog-styles";
4964
+ style.textContent = `
4965
+ dialog.jdf-calc-warning-dialog {
4966
+ border: none; border-radius: 8px; padding: 0;
4967
+ max-width: 480px; width: 90vw;
4968
+ box-shadow: 0 8px 32px rgba(0,0,0,0.2); overflow: hidden;
4969
+ }
4970
+ dialog.jdf-calc-warning-dialog::backdrop { background: rgba(0,0,0,0.35); }
4971
+ .jdf-calc-warning-header {
4972
+ background: #fff3e0; padding: 14px 20px;
4973
+ display: flex; align-items: center; justify-content: space-between;
4974
+ border-bottom: 1px solid #ffcc80;
4975
+ }
4976
+ .jdf-calc-warning-title { font-size: 15px; font-weight: 600; color: #e65100; margin: 0; font-family: inherit; }
4977
+ .jdf-calc-warning-close-btn {
4978
+ width: 28px; height: 28px; border: none; background: transparent;
4979
+ font-size: 20px; line-height: 1; cursor: pointer; color: #666;
4980
+ border-radius: 4px; display: flex; align-items: center; justify-content: center;
4981
+ padding: 0; font-family: inherit;
4982
+ }
4983
+ .jdf-calc-warning-close-btn:hover { background: #ffe0b2; color: #e65100; }
4984
+ .jdf-calc-warning-body { padding: 20px; font-family: inherit; font-size: 13px; color: #333; }
4985
+ .jdf-calc-warning-summary { margin: 0 0 12px 0; font-weight: 600; }
4986
+ .jdf-calc-warning-table { width: 100%; border-collapse: collapse; font-size: 13px; font-family: inherit; }
4987
+ .jdf-calc-warning-table tr:not(:last-child) td { border-bottom: 1px solid #f0f0f0; }
4988
+ .jdf-calc-warning-table td { padding: 6px 4px; vertical-align: top; }
4989
+ .jdf-calc-warning-sign { font-weight: 600; white-space: nowrap; }
4990
+ .jdf-calc-warning-sign.added { color: #2e7d32; }
4991
+ .jdf-calc-warning-sign.subtracted { color: #c62828; }
4992
+ `;
4993
+ document.head.appendChild(style);
4994
+ }
4995
+ _openCalculationWarningDialog(e2, mismatch) {
4996
+ var _a;
4997
+ e2.stopPropagation();
4998
+ this._ensureCalcWarningDialogStyles();
4999
+ const rowsHtml = mismatch.children.map((child) => `
5000
+ <tr>
5001
+ <td>${this._escapeHtml(child.label)}</td>
5002
+ <td>${this._escapeHtml(String(child.value))}</td>
5003
+ <td>${this._escapeHtml(child.balance || "—")}</td>
5004
+ <td class="jdf-calc-warning-sign ${child.weight === 1 ? "added" : "subtracted"}">
5005
+ ${this._escapeHtml(child.weight === 1 ? I18n.t("calculationWarning.added") : I18n.t("calculationWarning.subtracted"))}
5006
+ </td>
5007
+ </tr>
5008
+ `).join("");
5009
+ const dialog = document.createElement("dialog");
5010
+ dialog.className = "jdf-calc-warning-dialog";
5011
+ dialog.innerHTML = `
5012
+ <div class="jdf-calc-warning-header">
5013
+ <h3 class="jdf-calc-warning-title">⚠️ ${this._escapeHtml(I18n.t("calculationWarning.title"))}</h3>
5014
+ <button class="jdf-calc-warning-close-btn" type="button" aria-label="${this._escapeHtml(I18n.t("conceptInfo.close"))}">×</button>
5015
+ </div>
5016
+ <div class="jdf-calc-warning-body">
5017
+ <p class="jdf-calc-warning-summary">${this._escapeHtml(mismatch.message)}</p>
5018
+ <table class="jdf-calc-warning-table">${rowsHtml}</table>
5019
+ </div>
5020
+ `;
5021
+ document.body.appendChild(dialog);
5022
+ (_a = dialog.querySelector(".jdf-calc-warning-close-btn")) == null ? void 0 : _a.addEventListener("click", () => dialog.close());
5023
+ dialog.addEventListener("click", (ev) => {
5024
+ const rect = dialog.getBoundingClientRect();
5025
+ if (ev.clientX < rect.left || ev.clientX > rect.right || ev.clientY < rect.top || ev.clientY > rect.bottom) {
5026
+ dialog.close();
5027
+ }
5028
+ });
5029
+ dialog.addEventListener("close", () => document.body.removeChild(dialog));
5030
+ dialog.showModal();
5031
+ }
4937
5032
  render() {
4938
5033
  const hasChildren = this.concept.children && this.concept.children.length > 0;
4939
5034
  const level = this.concept.level || 0;
@@ -4978,8 +5073,17 @@ let JupiterConceptTree = class extends LitElement {
4978
5073
  const shouldShowField = !isAbstract && field2;
4979
5074
  const storedUnit = (_b = (_a = this.unitData) == null ? void 0 : _a[this.concept.id]) == null ? void 0 : _b[column2.id];
4980
5075
  const storedDecimals = (_d = (_c = this.decimalsData) == null ? void 0 : _c[this.concept.id]) == null ? void 0 : _d[column2.id];
5076
+ const calcMismatch = this.mode !== "readonly" ? (_e = this.calculationMismatches) == null ? void 0 : _e.get(`${this.concept.id}__${column2.id}`) : void 0;
4981
5077
  return html`
4982
- <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""} ${this.highlightType && column2.id === this.highlightColumnId ? "highlight-" + this.highlightType : ""} ${((_e = this.calculationErrorKeys) == null ? void 0 : _e.has(`${this.concept.id}__${column2.id}`)) ? "calc-error" : ""} ${this.rowFocused ? "row-focused" : ""}">
5078
+ <td class="field-cell ${!shouldShowField ? "empty" : ""} ${isAbstract ? "abstract-row" : ""} ${this.highlightType && column2.id === this.highlightColumnId ? "highlight-" + this.highlightType : ""} ${calcMismatch ? "calc-warning" : ""} ${this.rowFocused ? "row-focused" : ""}">
5079
+ ${calcMismatch ? html`
5080
+ <button
5081
+ class="calc-warning-badge"
5082
+ type="button"
5083
+ title="${calcMismatch.message}"
5084
+ @click="${(e2) => this._openCalculationWarningDialog(e2, calcMismatch)}"
5085
+ >!</button>
5086
+ ` : ""}
4983
5087
  ${shouldShowField ? html`
4984
5088
  <jupiter-form-field
4985
5089
  .field="${field2}"
@@ -5116,6 +5220,7 @@ JupiterConceptTree.styles = css`
5116
5220
  }
5117
5221
 
5118
5222
  .field-cell {
5223
+ position: relative;
5119
5224
  vertical-align: middle;
5120
5225
  padding: 2px 6px;
5121
5226
  border: 1px solid var(--primaryTextColor, var(--jupiter-border-color, #ddd));
@@ -5190,8 +5295,35 @@ JupiterConceptTree.styles = css`
5190
5295
  background: rgba(25, 118, 210, 0.07);
5191
5296
  }
5192
5297
 
5193
- .field-cell.calc-error {
5194
- box-shadow: inset 0 0 0 2px var(--jupiter-error-color, #d32f2f);
5298
+ /* Non-blocking JDF-036 live total/debit-credit mismatch warning — deliberately amber, distinct
5299
+ from any future genuinely-blocking calculation error, which should use a red style instead. */
5300
+ .field-cell.calc-warning {
5301
+ box-shadow: inset 0 0 0 2px var(--jupiter-warning-color, #ff9800);
5302
+ }
5303
+
5304
+ .calc-warning-badge {
5305
+ position: absolute;
5306
+ top: 2px;
5307
+ right: 2px;
5308
+ width: 16px;
5309
+ height: 16px;
5310
+ border-radius: 50%;
5311
+ border: none;
5312
+ background: var(--jupiter-warning-color, #ff9800);
5313
+ color: #fff;
5314
+ font-size: 10px;
5315
+ font-weight: 700;
5316
+ line-height: 1;
5317
+ padding: 0;
5318
+ display: flex;
5319
+ align-items: center;
5320
+ justify-content: center;
5321
+ cursor: pointer;
5322
+ z-index: 3;
5323
+ }
5324
+
5325
+ .calc-warning-badge:hover {
5326
+ background: #e65100;
5195
5327
  }
5196
5328
 
5197
5329
  /* Row-level highlight while a field in this row has focus. Applied to every
@@ -5322,7 +5454,7 @@ __decorateClass$5([
5322
5454
  ], JupiterConceptTree.prototype, "highlightColumnId", 2);
5323
5455
  __decorateClass$5([
5324
5456
  n2({ type: Object })
5325
- ], JupiterConceptTree.prototype, "calculationErrorKeys", 2);
5457
+ ], JupiterConceptTree.prototype, "calculationMismatches", 2);
5326
5458
  __decorateClass$5([
5327
5459
  n2({ type: String })
5328
5460
  ], JupiterConceptTree.prototype, "language", 2);
@@ -6027,12 +6159,18 @@ let JupiterFormSection = class extends LitElement {
6027
6159
  this._boundFieldBlur = (e2) => {
6028
6160
  this._clearHighlights();
6029
6161
  this._focusedConceptId = null;
6162
+ if (this.mode === "readonly")
6163
+ return;
6164
+ const detail = e2.detail;
6165
+ if ((detail == null ? void 0 : detail.conceptId) && (detail == null ? void 0 : detail.columnId)) {
6166
+ this._runCalculationCheck(detail.conceptId, detail.columnId);
6167
+ }
6030
6168
  };
6031
6169
  this._expandedConcepts = /* @__PURE__ */ new Set();
6032
6170
  this._allTreeExpanded = false;
6033
6171
  this._highlightMap = /* @__PURE__ */ new Map();
6034
6172
  this._focusedConceptId = null;
6035
- this._calculationErrorKeys = /* @__PURE__ */ new Set();
6173
+ this._calculationMismatches = /* @__PURE__ */ new Map();
6036
6174
  this._totalChildrenMap = /* @__PURE__ */ new Map();
6037
6175
  this._memberParentMap = /* @__PURE__ */ new Map();
6038
6176
  this._totalConceptMap = /* @__PURE__ */ new Map();
@@ -6340,50 +6478,100 @@ let JupiterFormSection = class extends LitElement {
6340
6478
  return;
6341
6479
  const totalConcept = this._totalConceptMap.get(totalConceptId);
6342
6480
  const totalRaw = (_a = this.formData[totalConceptId]) == null ? void 0 : _a[columnId];
6343
- const errorKey = `${totalConceptId}__${columnId}`;
6481
+ const key = `${totalConceptId}__${columnId}`;
6344
6482
  if (totalRaw === null || totalRaw === void 0 || totalRaw === "") {
6345
- if (this._calculationErrorKeys.has(errorKey)) {
6346
- const next2 = new Set(this._calculationErrorKeys);
6347
- next2.delete(errorKey);
6348
- this._calculationErrorKeys = next2;
6349
- }
6483
+ this._clearCalculationMismatch(key);
6350
6484
  return;
6351
6485
  }
6352
6486
  const totalValue = parseFloat(totalRaw);
6353
- if (isNaN(totalValue))
6487
+ if (isNaN(totalValue)) {
6488
+ this._clearCalculationMismatch(key);
6354
6489
  return;
6490
+ }
6355
6491
  const children = this._totalChildConceptsMap.get(totalConceptId) || [];
6356
- const childData = children.map((child) => {
6357
- var _a2;
6358
- return {
6359
- value: (_a2 = this.formData[child.id]) == null ? void 0 : _a2[columnId],
6360
- balance: child.balance
6361
- };
6362
- });
6363
- const isValid = JupiterFormSection._checkTotal(totalValue, childData, totalConcept.balance);
6364
- const next = new Set(this._calculationErrorKeys);
6365
- if (!isValid) {
6366
- next.add(errorKey);
6367
- } else {
6368
- next.delete(errorKey);
6492
+ const { calculatedSum, hasAnyValue, breakdown } = JupiterFormSection._buildCalculationBreakdown(
6493
+ children,
6494
+ this.formData,
6495
+ columnId,
6496
+ totalConcept.balance
6497
+ );
6498
+ if (!hasAnyValue || JupiterFormSection._checkTotal(totalValue, calculatedSum)) {
6499
+ this._clearCalculationMismatch(key);
6500
+ return;
6369
6501
  }
6370
- this._calculationErrorKeys = next;
6502
+ const detailWithoutMessage = {
6503
+ totalConceptId,
6504
+ totalLabel: totalConcept.label,
6505
+ columnId,
6506
+ sectionId: this.section.id,
6507
+ enteredTotal: totalValue,
6508
+ calculatedSum,
6509
+ children: breakdown
6510
+ };
6511
+ const detail = {
6512
+ ...detailWithoutMessage,
6513
+ message: JupiterFormSection._buildMismatchMessage(detailWithoutMessage)
6514
+ };
6515
+ const next = new Map(this._calculationMismatches);
6516
+ next.set(key, detail);
6517
+ this._calculationMismatches = next;
6518
+ this._dispatchCalculationMismatchChanged(key, detail);
6519
+ }
6520
+ _clearCalculationMismatch(key) {
6521
+ if (!this._calculationMismatches.has(key))
6522
+ return;
6523
+ const next = new Map(this._calculationMismatches);
6524
+ next.delete(key);
6525
+ this._calculationMismatches = next;
6526
+ this._dispatchCalculationMismatchChanged(key, null);
6527
+ }
6528
+ _dispatchCalculationMismatchChanged(key, mismatch) {
6529
+ this.dispatchEvent(new CustomEvent("calculation-mismatch-changed", {
6530
+ detail: { key, mismatch },
6531
+ bubbles: true,
6532
+ composed: true
6533
+ }));
6371
6534
  }
6372
- static _checkTotal(totalValue, children, totalBalance) {
6535
+ /** Single source of truth for the debit/credit weighting used both to validate the total and to build the breakdown shown to the user. */
6536
+ static _resolveWeight(totalBalance, childBalance) {
6537
+ return !totalBalance || !childBalance || totalBalance === childBalance ? 1 : -1;
6538
+ }
6539
+ static _buildCalculationBreakdown(children, formData, columnId, totalBalance) {
6540
+ var _a;
6373
6541
  let calculatedSum = 0;
6374
6542
  let hasAnyValue = false;
6543
+ const breakdown = [];
6375
6544
  for (const child of children) {
6376
- const val = parseFloat(child.value);
6545
+ const val = parseFloat((_a = formData[child.id]) == null ? void 0 : _a[columnId]);
6377
6546
  if (isNaN(val))
6378
6547
  continue;
6379
6548
  hasAnyValue = true;
6380
- const weight = !totalBalance || !child.balance || totalBalance === child.balance ? 1 : -1;
6549
+ const weight = JupiterFormSection._resolveWeight(totalBalance, child.balance);
6381
6550
  calculatedSum += weight * val;
6551
+ breakdown.push({ conceptId: child.id, label: child.label, value: val, balance: child.balance, weight });
6382
6552
  }
6383
- if (!hasAnyValue)
6384
- return true;
6553
+ return { calculatedSum, hasAnyValue, breakdown };
6554
+ }
6555
+ static _checkTotal(totalValue, calculatedSum) {
6385
6556
  return Math.abs(calculatedSum - totalValue) < 0.01;
6386
6557
  }
6558
+ static _formatNumber(n3) {
6559
+ return Number.isInteger(n3) ? String(n3) : n3.toFixed(2);
6560
+ }
6561
+ static _buildMismatchMessage(detail) {
6562
+ const summary = I18n.t("calculationWarning.summaryLine", {
6563
+ label: detail.totalLabel,
6564
+ calculated: JupiterFormSection._formatNumber(detail.calculatedSum),
6565
+ entered: JupiterFormSection._formatNumber(detail.enteredTotal)
6566
+ });
6567
+ if (detail.children.length === 0)
6568
+ return summary;
6569
+ const childLines = detail.children.map((child) => I18n.t(
6570
+ child.weight === 1 ? "calculationWarning.childAdded" : "calculationWarning.childSubtracted",
6571
+ { label: child.label, value: JupiterFormSection._formatNumber(child.value) }
6572
+ ));
6573
+ return `${summary} ${I18n.t("calculationWarning.childrenPrefix")} ${childLines.join("; ")}`;
6574
+ }
6387
6575
  _handleFieldFocusForHighlight(event) {
6388
6576
  var _a, _b;
6389
6577
  const conceptId = (_a = event.detail) == null ? void 0 : _a.conceptId;
@@ -6479,7 +6667,7 @@ let JupiterFormSection = class extends LitElement {
6479
6667
  .highlightType="${(_a2 = this._highlightMap.get(instanceConcept.id)) == null ? void 0 : _a2.type}"
6480
6668
  .highlightColumnId="${(_b = this._highlightMap.get(instanceConcept.id)) == null ? void 0 : _b.columnId}"
6481
6669
  .rowFocused="${this._focusedConceptId === instanceConcept.id}"
6482
- .calculationErrorKeys="${this._calculationErrorKeys}"
6670
+ .calculationMismatches="${this._calculationMismatches}"
6483
6671
  @field-change="${this._handleFieldChange}"
6484
6672
  @field-focus="${this._handleFieldFocusForHighlight}"
6485
6673
  @period-change="${this._handlePeriodChange}"
@@ -7052,7 +7240,7 @@ __decorateClass$3([
7052
7240
  ], JupiterFormSection.prototype, "_focusedConceptId", 2);
7053
7241
  __decorateClass$3([
7054
7242
  r()
7055
- ], JupiterFormSection.prototype, "_calculationErrorKeys", 2);
7243
+ ], JupiterFormSection.prototype, "_calculationMismatches", 2);
7056
7244
  JupiterFormSection = __decorateClass$3([
7057
7245
  t$1("jupiter-form-section")
7058
7246
  ], JupiterFormSection);
@@ -9095,6 +9283,7 @@ let JupiterDynamicForm = class extends LitElement {
9095
9283
  this._valid = true;
9096
9284
  this._submitted = false;
9097
9285
  this._xbrlFormErrors = [];
9286
+ this._calculationWarnings = /* @__PURE__ */ new Map();
9098
9287
  this._showErrorPopup = false;
9099
9288
  this._submitDisabled = false;
9100
9289
  this._allSections = [];
@@ -9142,6 +9331,9 @@ let JupiterDynamicForm = class extends LitElement {
9142
9331
  const customEvent = e2;
9143
9332
  this._handleFieldBlur(customEvent);
9144
9333
  });
9334
+ this.addEventListener("calculation-mismatch-changed", (e2) => {
9335
+ this._handleCalculationMismatchChanged(e2);
9336
+ });
9145
9337
  document.addEventListener("click", () => {
9146
9338
  if (this._showRoleContextMenu) {
9147
9339
  this._showRoleContextMenu = false;
@@ -9929,9 +10121,29 @@ let JupiterDynamicForm = class extends LitElement {
9929
10121
  }
9930
10122
  }
9931
10123
  }
10124
+ errors.push(...Array.from(this._calculationWarnings.values()));
9932
10125
  this._errors = errors;
9933
10126
  this._valid = errors.filter((e2) => e2.severity === "error").length === 0;
9934
10127
  }
10128
+ _handleCalculationMismatchChanged(event) {
10129
+ const { key, mismatch } = event.detail;
10130
+ const next = new Map(this._calculationWarnings);
10131
+ if (mismatch) {
10132
+ next.set(key, {
10133
+ fieldId: `${mismatch.totalConceptId}__${mismatch.columnId}`,
10134
+ conceptId: mismatch.totalConceptId,
10135
+ columnId: mismatch.columnId,
10136
+ message: mismatch.message,
10137
+ severity: "warning",
10138
+ rule: { type: "custom", message: mismatch.message, severity: "warning" },
10139
+ details: mismatch
10140
+ });
10141
+ } else {
10142
+ next.delete(key);
10143
+ }
10144
+ this._calculationWarnings = next;
10145
+ this._validateForm();
10146
+ }
9935
10147
  _handleFieldChange(event) {
9936
10148
  const { fieldId, conceptId, columnId, value } = event.detail;
9937
10149
  console.log(`📝 Field change: conceptId=${conceptId}, columnId=${columnId}, value=${value}, fieldId=${fieldId}`);
@@ -12643,11 +12855,11 @@ let JupiterDynamicForm = class extends LitElement {
12643
12855
  <div class="form-sections">
12644
12856
  <!-- Validation Summary -->
12645
12857
  ${showValidationSummary ? html`
12646
- <div class="validation-summary">
12647
- <h4 class="validation-summary-title">${I18n.t("validation.summary")}</h4>
12858
+ <div class="validation-summary ${errorCount === 0 ? "warnings-only" : ""}">
12859
+ <h4 class="validation-summary-title">${errorCount > 0 ? I18n.t("validation.summary") : I18n.t("calculationWarning.title")}</h4>
12648
12860
  <ul class="validation-summary-list">
12649
- ${this._errors.filter((e2) => e2.severity === "error").map((error2) => html`
12650
- <li class="validation-summary-item">${error2.message}</li>
12861
+ ${this._errors.filter((e2) => e2.severity === "error" || e2.severity === "warning" && this.mode !== "readonly").map((error2) => html`
12862
+ <li class="validation-summary-item ${error2.severity}">${error2.severity === "warning" ? "⚠️ " : ""}${error2.message}</li>
12651
12863
  `)}
12652
12864
  </ul>
12653
12865
  </div>
@@ -12807,11 +13019,11 @@ let JupiterDynamicForm = class extends LitElement {
12807
13019
  <div class="form-sections">
12808
13020
  <!-- Validation Summary -->
12809
13021
  ${showValidationSummary ? html`
12810
- <div class="validation-summary">
12811
- <h4 class="validation-summary-title">Please fix the following errors:</h4>
13022
+ <div class="validation-summary ${errorCount === 0 ? "warnings-only" : ""}">
13023
+ <h4 class="validation-summary-title">${errorCount > 0 ? I18n.t("validation.summary") : I18n.t("calculationWarning.title")}</h4>
12812
13024
  <ul class="validation-summary-list">
12813
- ${this._errors.filter((e2) => e2.severity === "error").map((error2) => html`
12814
- <li class="validation-summary-item">${error2.message}</li>
13025
+ ${this._errors.filter((e2) => e2.severity === "error" || e2.severity === "warning" && this.mode !== "readonly").map((error2) => html`
13026
+ <li class="validation-summary-item ${error2.severity}">${error2.severity === "warning" ? "⚠️ " : ""}${error2.message}</li>
12815
13027
  `)}
12816
13028
  </ul>
12817
13029
  </div>
@@ -13161,8 +13373,9 @@ let JupiterDynamicForm = class extends LitElement {
13161
13373
  render() {
13162
13374
  var _a;
13163
13375
  const errorCount = this._errors.filter((e2) => e2.severity === "error").length;
13376
+ const warningCount = this.mode === "readonly" ? 0 : this._errors.filter((e2) => e2.severity === "warning").length;
13164
13377
  const config = this.config || {};
13165
- const showValidationSummary = config.showValidationSummary !== false && errorCount > 0 && this._submitted;
13378
+ const showValidationSummary = config.showValidationSummary !== false && (errorCount > 0 && this._submitted || warningCount > 0);
13166
13379
  const schema = this._currentSchema;
13167
13380
  if (!schema) {
13168
13381
  return html`<div>${I18n.t("form.loading")}</div>`;
@@ -13227,7 +13440,7 @@ let JupiterDynamicForm = class extends LitElement {
13227
13440
  @click="${() => this.dispatchEvent(new CustomEvent("showPreview", { bubbles: true, composed: true }))}"
13228
13441
  ?disabled="${this.disabled || this.readonly}"
13229
13442
  >
13230
- ${I18n.t("form.preview")}
13443
+ ${I18n.t("form.download")}
13231
13444
  </button>
13232
13445
  ` : ""}
13233
13446
 
@@ -13427,6 +13640,21 @@ JupiterDynamicForm.styles = css`
13427
13640
  margin-bottom: 4px;
13428
13641
  }
13429
13642
 
13643
+ /* JDF-036: when the summary contains only non-blocking calculation warnings (no blocking
13644
+ errors), style the whole box amber rather than error-red so it doesn't read as blocking. */
13645
+ .validation-summary.warnings-only {
13646
+ background: var(--jupiter-warning-background, #fff3e0);
13647
+ border-color: var(--jupiter-warning-color, #ff9800);
13648
+ }
13649
+
13650
+ .validation-summary.warnings-only .validation-summary-title {
13651
+ color: var(--jupiter-warning-color, #ff9800);
13652
+ }
13653
+
13654
+ .validation-summary-item.warning {
13655
+ color: var(--jupiter-warning-color, #ff9800);
13656
+ }
13657
+
13430
13658
  .form-actions button {
13431
13659
  padding: 10px 20px;
13432
13660
  border: none;
@@ -14277,6 +14505,9 @@ __decorateClass([
14277
14505
  __decorateClass([
14278
14506
  r()
14279
14507
  ], JupiterDynamicForm.prototype, "_xbrlFormErrors", 2);
14508
+ __decorateClass([
14509
+ r()
14510
+ ], JupiterDynamicForm.prototype, "_calculationWarnings", 2);
14280
14511
  __decorateClass([
14281
14512
  r()
14282
14513
  ], JupiterDynamicForm.prototype, "_showErrorPopup", 2);