ftvuzw-configuration-builder 0.1.0

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.
Files changed (4) hide show
  1. package/LICENSE +31 -0
  2. package/README.md +211 -0
  3. package/dist/index.js +929 -0
  4. package/package.json +38 -0
package/dist/index.js ADDED
@@ -0,0 +1,929 @@
1
+ var ot=Object.defineProperty;var rt=(o,e)=>{for(var t in e)ot(o,t,{get:e[t],enumerable:!0})};var Me=`
2
+ :host {
3
+ --db-primary: #3f51b5;
4
+ --db-primary-hover: #303f9f;
5
+ --db-border: #c4c6d0;
6
+ --db-bg: #f4f5f7;
7
+ --db-surface: #e0e2ec;
8
+ --db-card-bg: #ffffff;
9
+ --db-text: #1d2330;
10
+ --db-text-muted: #5c6270;
11
+ --db-radius: 8px;
12
+ --db-color-readonly: #7f8c8d;
13
+ --db-color-hid: #d35400;
14
+ --db-color-opt: #2980b9;
15
+ --db-color-calc: #008080;
16
+ --db-color-clr: #e91e63;
17
+ --db-color-val: #8e44ad;
18
+ --db-color-email: #0277bd;
19
+ --db-transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
20
+
21
+ display: block;
22
+ font-family: var(--db-font, 'Inter', system-ui, sans-serif);
23
+ color: var(--db-text);
24
+ box-sizing: border-box;
25
+ }
26
+ *, *::before, *::after { box-sizing: border-box; }
27
+
28
+ .db-root { width: 100%; }
29
+ .db-layout { display: flex; align-items: flex-start; gap: 12px; width: 100%; }
30
+ .db-main { flex: 1; min-width: 0; }
31
+
32
+ /* Saved-config sidebar */
33
+ .db-sidebar { flex: 0 0 200px; width: 200px; background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: var(--db-radius); padding: 10px; position: sticky; top: 8px; }
34
+ .db-sidebar-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
35
+ .db-sidebar-actions { display: inline-flex; align-items: center; gap: 4px; }
36
+ .db-sidebar-actions .db-new-btn { display: inline-flex; align-items: center; justify-content: center; }
37
+ .db-sidebar-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--db-text-muted); }
38
+ .db-save-btn { display: inline-flex; align-items: center; gap: 4px; background: var(--db-primary); color: #fff; border: none; border-radius: 6px; padding: 4px 10px; font-size: 12px; font-weight: 600; cursor: pointer; flex-shrink: 0; }
39
+ .db-save-btn:hover { background: var(--db-primary-hover); }
40
+ .db-save-btn .db-icon { width: 14px; height: 14px; }
41
+ .db-new-btn { width: 24px; height: 24px; background: var(--db-primary); color: #fff; border: none; border-radius: 6px; font-size: 16px; line-height: 1; cursor: pointer; flex-shrink: 0; }
42
+ .db-new-btn:hover { background: var(--db-primary-hover); }
43
+ .db-store-list { display: flex; flex-direction: column; gap: 4px; }
44
+ .db-store-empty { font-size: 12px; color: var(--db-text-muted); font-style: italic; padding: 4px 2px; }
45
+ .db-store-item { display: flex; align-items: center; gap: 4px; border-radius: 6px; flex-wrap: wrap; }
46
+ .db-store-item .delete-confirm-wrapper { padding: 0 4px 4px; }
47
+ .db-store-item.active { background: rgba(63,81,181,0.10); }
48
+ .db-store-load { flex: 1; min-width: 0; text-align: left; background: transparent; border: none; cursor: pointer; font-family: inherit; font-size: 13px; color: var(--db-text); padding: 6px 8px; border-radius: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
49
+ .db-store-load:hover { background: rgba(0,0,0,0.05); }
50
+ .db-store-del { flex: none; background: transparent; border: none; color: var(--db-text-muted); cursor: pointer; padding: 4px; border-radius: 6px; display: inline-flex; }
51
+ .db-store-del:hover { color: #ef4444; background: #fef2f2; }
52
+
53
+ /* Top config bar */
54
+ .top-bar-config {
55
+ width: 100%;
56
+ min-height: 44px;
57
+ background: var(--db-card-bg);
58
+ border: 1px solid var(--db-border);
59
+ border-radius: var(--db-radius);
60
+ padding: 6px 16px;
61
+ margin-bottom: 12px;
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: space-between;
65
+ gap: 16px;
66
+ flex-wrap: wrap;
67
+ }
68
+ .config-name-section { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
69
+ /* Roles group: own column, fixed at 25vw, chips/inputs wrap when there are many. */
70
+ .roles-group { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; width: 38vw; }
71
+ .config-name-input {
72
+ border: none; background: transparent; font-weight: 600; font-size: 14px;
73
+ color: var(--db-text); padding: 4px 8px; width: 200px;
74
+ }
75
+ .config-name-input:focus { outline: none; border-bottom: 2px solid var(--db-primary); }
76
+ .top-bar-config .divider { width: 1px; height: 20px; background: var(--db-border); }
77
+ .roles-section { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
78
+ .roles-label { font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--db-text-muted); letter-spacing: 0.05em; }
79
+ .roles-chips-wrapper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
80
+ .role-chip {
81
+ display: inline-flex; align-items: center; background: #f1f5f9; border: 1px solid #e2e8f0;
82
+ color: #475569; padding: 2px 8px; border-radius: 999px; font-size: 12px; font-weight: 500; gap: 4px;
83
+ }
84
+ .role-chip .delete-role-btn { cursor: pointer; color: #94a3b8; border: none; background: transparent; padding: 0; font-size: 14px; line-height: 1; }
85
+ .role-chip .delete-role-btn:hover { color: #ef4444; }
86
+ .add-role-section { display: flex; align-items: center; gap: 6px; }
87
+ .add-role-section input {
88
+ width: 110px; height: 28px; font-size: 12px; padding: 4px 8px;
89
+ border: 1px solid var(--db-border); border-radius: var(--db-radius); background: #fff;
90
+ }
91
+ .add-role-btn-icon {
92
+ width: 28px; height: 28px; background: var(--db-primary); color: #fff; border: none;
93
+ border-radius: var(--db-radius); font-size: 16px; cursor: pointer; flex-shrink: 0;
94
+ }
95
+ .add-role-btn-icon:hover { background: var(--db-primary-hover); }
96
+
97
+ /* Tabs (Angular-Material style) \u2014 sit in the top bar between name and roles */
98
+ .db-tabs { position: relative; display: flex; align-self: stretch; gap: 2px; flex-shrink: 0; margin: -6px 0; }
99
+ .db-tab {
100
+ position: relative; display: flex; align-items: center; background: transparent; border: none;
101
+ cursor: pointer; font-family: inherit; font-size: 13px; font-weight: 600; color: var(--db-text-muted);
102
+ padding: 0 18px; transition: color 0.2s, background-color 0.2s; white-space: nowrap;
103
+ }
104
+ .db-tab:hover { background: rgba(63,81,181,0.06); color: var(--db-text); }
105
+ .db-tab.active { color: var(--db-primary); }
106
+ .db-tab-ink {
107
+ position: absolute; bottom: 0; left: 0; width: 0; height: 2px; background: var(--db-primary);
108
+ transition: left 0.25s cubic-bezier(0.4,0,0.2,1), width 0.25s cubic-bezier(0.4,0,0.2,1);
109
+ }
110
+
111
+ /* Tab panels + shared view chrome */
112
+ .db-panel { width: 100%; }
113
+ .view-empty { padding: 48px 24px; text-align: center; color: var(--db-text-muted); font-size: 14px; background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: 12px; }
114
+ .view-muted { color: var(--db-text-muted); }
115
+ .view-tag { display: inline-block; background: #eef2ff; color: var(--db-primary); border-radius: 999px; padding: 1px 8px; font-size: 11px; font-weight: 600; margin: 1px 0; }
116
+
117
+ /* Table view */
118
+ .view-table { width: 100%; border-collapse: collapse; background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: 12px; overflow: hidden; font-size: 13px; }
119
+ .view-table th, .view-table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--db-border); vertical-align: top; }
120
+ .view-table th { background: #f8fafc; font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--db-text-muted); font-weight: 700; }
121
+ .view-table tbody tr:last-child td { border-bottom: none; }
122
+ .view-table tbody tr:hover { background: #f8fafc; }
123
+ .view-table code { background: #f1f5f9; padding: 1px 5px; border-radius: 4px; font-size: 12px; }
124
+ .view-table .table-w { width: 72px; font-size: 12px; padding: 4px 6px; }
125
+ .view-table .table-check { text-align: center; }
126
+ .view-table .table-check input { width: 16px; height: 16px; cursor: pointer; }
127
+ .view-json-title { font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--db-text-muted); margin: 16px 0 6px; }
128
+
129
+ /* Chart view (Chart.js config builder) */
130
+ .chart-config { background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: 12px; padding: 16px; margin-bottom: 12px; }
131
+ .chart-intro { font-size: 12px; color: var(--db-text-muted); margin: 0 0 12px; }
132
+ .chart-intro b { color: var(--db-text); }
133
+ .chart-fields { display: flex; flex-wrap: wrap; gap: 16px; }
134
+ .chart-field { display: flex; flex-direction: column; gap: 4px; max-width: 220px; }
135
+ .chart-field label { font-size: 11px; font-weight: 700; letter-spacing: 0.03em; color: var(--db-primary); }
136
+ .chart-field select { width: 200px; }
137
+ .chart-hint { font-size: 11px; color: var(--db-text-muted); }
138
+ .chart-summary { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--db-border); font-size: 13px; font-weight: 600; color: var(--db-text); }
139
+ .chart-preview { position: relative; height: 340px; background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: 12px; padding: 16px; }
140
+ .chart-note { font-size: 12px; color: var(--db-text-muted); margin-top: 8px; }
141
+
142
+ /* Paste-JSON modal */
143
+ .db-modal-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.45); display: flex; align-items: center; justify-content: center; z-index: 1000; }
144
+ .db-modal { background: var(--db-card-bg); border-radius: 12px; width: min(640px, 92vw); max-height: 85vh; display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25); padding: 20px; }
145
+ .db-modal-head { display: flex; align-items: center; justify-content: space-between; font-size: 15px; font-weight: 700; color: var(--db-text); margin-bottom: 8px; }
146
+ .db-modal-x { background: transparent; border: none; cursor: pointer; color: var(--db-text-muted); display: inline-flex; padding: 2px; }
147
+ .db-modal-x:hover { color: var(--db-text); }
148
+ .db-modal-hint { font-size: 12px; color: var(--db-text-muted); margin: 0 0 12px; }
149
+ .db-modal-hint code { background: #f1f5f9; padding: 1px 5px; border-radius: 4px; }
150
+ .db-json-input { width: 100%; flex: 1; min-height: 300px; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; line-height: 1.5; padding: 12px; border: 1px solid var(--db-border); border-radius: 8px; background: #fff; color: var(--db-text); resize: vertical; }
151
+ .db-json-err { color: #ef4444; font-size: 12px; min-height: 16px; margin-top: 8px; white-space: pre-wrap; }
152
+ .db-modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
153
+
154
+ /* Preview view \u2014 live run of the dialog (form + data table + chart) */
155
+ .pv-grid { display: grid; grid-template-columns: minmax(320px, 1fr) minmax(360px, 1.2fr); gap: 16px; align-items: start; }
156
+ @media (max-width: 900px) { .pv-grid { grid-template-columns: 1fr; } }
157
+ .pv-pane { background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: 12px; padding: 16px; }
158
+ .pv-pane-head { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--db-text-muted); margin-bottom: 12px; }
159
+ .pv-roles { display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px; max-width: 240px; }
160
+ .pv-roles select { width: 100%; font-size: 13px; padding: 7px 9px; border: 1px solid var(--db-border); border-radius: 6px; background: #fff; color: var(--db-text); font-family: inherit; }
161
+ .pv-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
162
+ .pv-field { display: flex; flex-direction: column; gap: 4px; padding-left: 0; border-left: 3px solid transparent; transition: border-color 0.15s ease; }
163
+ .pv-field.full { grid-column: 1 / -1; }
164
+ .pv-label { font-size: 11px; font-weight: 700; letter-spacing: 0.03em; color: var(--db-primary); }
165
+ .pv-field input[type="text"], .pv-field input[type="number"], .pv-field input[type="date"], .pv-field select, .pv-field textarea {
166
+ width: 100%; color: var(--db-text); font-size: 13px; padding: 7px 9px; border: 1px solid var(--db-border); border-radius: 6px; background: #fff; font-family: inherit; }
167
+ .pv-field textarea { resize: vertical; }
168
+ .pv-opts { display: flex; flex-wrap: wrap; gap: 10px; color: var(--db-text); }
169
+ .pv-opts label { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; }
170
+ /* Rule states applied live in the preview */
171
+ .pv-field.pv-colored { border-left-color: var(--pv-accent, transparent); padding-left: 8px; }
172
+ .pv-field.pv-colored .pv-label { color: var(--pv-accent); }
173
+ .pv-field.pv-readonly input, .pv-field.pv-readonly select, .pv-field.pv-readonly textarea { background: #f1f5f9; color: var(--db-text-muted); cursor: not-allowed; }
174
+ .pv-field input:disabled, .pv-field select:disabled, .pv-field textarea:disabled { background: #f1f5f9; color: var(--db-text-muted); cursor: not-allowed; }
175
+ .pv-field.pv-invalid input, .pv-field.pv-invalid select, .pv-field.pv-invalid textarea { border-color: #ef4444; }
176
+ .pv-error { font-size: 11px; color: #ef4444; min-height: 0; }
177
+ .pv-error:empty { display: none; }
178
+ .pv-formerr { margin-top: 12px; padding: 8px 12px; border-radius: 6px; background: #fef2f2; border: 1px solid #fecaca; color: #b91c1c; font-size: 12px; font-weight: 600; }
179
+ .pv-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
180
+ .pv-btn { background: var(--db-primary); color: #fff; border: none; border-radius: 6px; padding: 8px 14px; font-size: 13px; font-weight: 600; cursor: pointer; }
181
+ .pv-btn:hover { background: var(--db-primary-hover); }
182
+ .pv-btn.ghost { background: #fff; color: var(--db-text); border: 1px solid var(--db-border); }
183
+ .pv-btn.ghost:hover { background: #f1f5f9; }
184
+ .pv-del-cell { text-align: center; }
185
+ .pv-del { background: transparent; border: none; color: var(--db-text-muted); font-size: 13px; cursor: pointer; }
186
+ .pv-del:hover { color: #ef4444; }
187
+
188
+ /* Workflow view \u2014 ComfyUI-style node graph */
189
+ .wf-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
190
+ .wf-add { background: var(--db-primary); color: #fff; border: none; border-radius: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; }
191
+ .wf-add:hover { background: var(--db-primary-hover); }
192
+ .wf-add:disabled { background: #cbd5e1; cursor: not-allowed; }
193
+ .wf-zoom { display: inline-flex; align-items: center; gap: 4px; }
194
+ .wf-zoom button {
195
+ display: inline-flex; align-items: center; justify-content: center; gap: 4px;
196
+ min-width: 30px; background: #fff; color: var(--db-text); border: 1px solid var(--db-border);
197
+ border-radius: 6px; padding: 6px 10px; font-size: 12px; font-weight: 600; line-height: 1; cursor: pointer;
198
+ transition: var(--db-transition);
199
+ }
200
+ .wf-zoom button:hover { border-color: var(--db-primary); color: var(--db-primary); background: #f8fafc; }
201
+ .wf-hint { font-size: 11px; color: var(--db-text-muted); }
202
+ .wf-canvas {
203
+ position: relative; height: 520px; overflow: hidden; border: 1px solid var(--db-border); border-radius: 12px;
204
+ background-color: #fafbff; cursor: grab;
205
+ background-image: radial-gradient(circle, #c9cdda 1.1px, transparent 1.1px);
206
+ background-size: 18px 18px;
207
+ }
208
+ .wf-canvas:active { cursor: grabbing; }
209
+ .wf-content { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform-origin: 0 0; }
210
+ .wf-canvas-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--db-text-muted); font-size: 14px; pointer-events: none; }
211
+ .wf-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
212
+ .wf-edge { stroke: var(--db-primary); stroke-width: 2; fill: none; }
213
+ .wf-node {
214
+ position: absolute; background: #fff; border: 2px solid var(--db-border); border-radius: 10px;
215
+ box-shadow: 0 2px 8px rgba(0,0,0,0.08); user-select: none;
216
+ }
217
+ .wf-node.selected { border-color: var(--db-primary); box-shadow: 0 8px 22px rgba(63,81,181,0.28); }
218
+ .wf-node-head { display: flex; align-items: center; gap: 6px; padding: 8px 10px; cursor: grab; border-bottom: 1px solid var(--db-border); background: #f8fafc; border-radius: 8px 8px 0 0; }
219
+ .wf-node-head:active { cursor: grabbing; }
220
+ .wf-node-badge { flex: none; width: 18px; height: 18px; border-radius: 50%; background: var(--db-primary); color: #fff; font-size: 10px; font-weight: 700; display: flex; align-items: center; justify-content: center; }
221
+ .wf-node-badge-input {
222
+ flex: none;
223
+ width: 20px;
224
+ height: 20px;
225
+ border-radius: 50%;
226
+ background: var(--db-primary);
227
+ color: #fff;
228
+ font-size: 10px;
229
+ font-weight: 700;
230
+ text-align: center;
231
+ border: none;
232
+ padding: 0;
233
+ margin: 0;
234
+ display: inline-flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ cursor: pointer;
238
+ -moz-appearance: textfield;
239
+ }
240
+ .wf-node-badge-input::-webkit-outer-spin-button,
241
+ .wf-node-badge-input::-webkit-inner-spin-button {
242
+ -webkit-appearance: none;
243
+ margin: 0;
244
+ }
245
+ .wf-node-badge-input:focus {
246
+ outline: none;
247
+ background: var(--db-primary-hover);
248
+ box-shadow: 0 0 0 2px rgba(63,81,181,0.3);
249
+ }
250
+ .wf-node-title { font-size: 13px; font-weight: 600; color: var(--db-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
251
+ input.wf-node-title { flex: 1; min-width: 0; border: none; background: transparent; padding: 1px 4px; font-family: inherit; cursor: text; border-radius: 4px; }
252
+ input.wf-node-title:focus { outline: none; background: #fff; box-shadow: 0 0 0 2px var(--db-primary); }
253
+ input.wf-node-title::placeholder { color: var(--db-text-muted); font-weight: 400; }
254
+ .wf-node-body { padding: 8px 10px; font-size: 11px; color: var(--db-text-muted); cursor: grab; }
255
+ .wf-node.wf-connect-target { border-color: var(--db-primary); box-shadow: 0 0 0 3px rgba(63,81,181,0.25); }
256
+ .wf-port {
257
+ position: absolute; top: 50%; transform: translateY(-50%); width: 14px; height: 14px;
258
+ box-sizing: border-box; border-radius: 50%; background: #fff; border: 2px solid var(--db-primary); z-index: 3;
259
+ transition: var(--db-transition);
260
+ }
261
+ .wf-port-in { left: -8px; }
262
+ .wf-port-out { right: -8px; cursor: crosshair; }
263
+ .wf-port-out:hover { background: var(--db-primary); transform: translateY(-50%) scale(1.25); }
264
+ .wf-temp-edge { stroke-dasharray: 5 4; opacity: 0.85; pointer-events: none; }
265
+ /* Inspector */
266
+ .wf-inspector { margin-top: 12px; background: var(--db-card-bg); border: 1px solid var(--db-border); border-radius: 12px; padding: 14px; }
267
+ .wf-insp-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; font-size: 14px; }
268
+ .wf-insp-field { display: flex; flex-direction: column; gap: 4px; font-size: 11px; font-weight: 700; color: var(--db-text-muted); margin-bottom: 10px; max-width: 320px; }
269
+ .wf-insp-field input, .wf-insp-field select { font-weight: 400; color: var(--db-text); }
270
+ .wf-insp-sub { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--db-primary); margin: 12px 0 6px; }
271
+ .wf-insp-trans { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 6px 0; }
272
+ .wf-insp-trans select { width: auto; min-width: 110px; }
273
+ .wf-add-sm { margin-top: 8px; font-size: 11px; padding: 5px 10px; }
274
+ .wf-empty { font-size: 12px; color: var(--db-text-muted); font-style: italic; }
275
+ .wf-lbl { font-size: 11px; color: var(--db-text-muted); }
276
+ .wf-arrow { font-size: 16px; color: var(--db-primary); font-weight: 700; }
277
+ .wf-del { flex: none; background: transparent; border: none; color: var(--db-text-muted); cursor: pointer; padding: 4px; border-radius: 6px; display: inline-flex; }
278
+ .wf-del:hover { color: #ef4444; background: #fef2f2; }
279
+
280
+ /* Rows + grid */
281
+ .db-row {
282
+ display: flex; align-items: center; gap: 8px; width: 100%; margin-bottom: 8px;
283
+ box-sizing: border-box; border-radius: 12px; transition: all 0.2s ease;
284
+ }
285
+ .db-row.row-dragging { opacity: 0.4; }
286
+ .db-row.row-drag-over { box-shadow: 0 -4px 0 var(--db-primary); }
287
+ .row-drag-handle {
288
+ cursor: grab; color: #94a3b8; display: flex; align-items: center; justify-content: center;
289
+ width: 24px; height: 48px; border-radius: 6px; transition: all 0.2s ease; flex-shrink: 0;
290
+ }
291
+ .row-drag-handle:hover { background-color: rgba(0,0,0,0.05); color: var(--db-text); }
292
+ .row-drag-handle:active { cursor: grabbing; }
293
+ .row-drag-handle .db-icon { width: 18px; height: 18px; }
294
+ .showcase-grid-wrapper { width: 100%; min-width: 0; border-radius: 12px; transition: background-color 0.2s ease; }
295
+ .showcase-card.dragging { opacity: 0.4; }
296
+ .showcase-card.drag-over .card-inner { border: 2px dashed var(--db-primary); }
297
+ .showcase-grid {
298
+ display: grid; grid-template-columns: var(--grid-template, repeat(10, 1fr)); gap: 16px;
299
+ background: #fff; border: 1px solid var(--db-border); border-radius: 12px; padding: 16px;
300
+ align-items: start;
301
+ }
302
+ .showcase-card { position: relative; grid-column: span var(--card-width, 2); display: block; }
303
+ .card-inner {
304
+ background-color: var(--db-surface); border-radius: var(--db-radius); padding: 12px;
305
+ display: flex; flex-direction: column; gap: 8px; cursor: pointer; opacity: 0.8;
306
+ transition:
307
+ transform 0.4s cubic-bezier(0.4, 0, 0.2, 1),
308
+ background-color 0.4s cubic-bezier(0.4, 0, 0.2, 1),
309
+ border-color 0.4s cubic-bezier(0.4, 0, 0.2, 1),
310
+ box-shadow 0.4s cubic-bezier(0.4, 0, 0.2, 1),
311
+ opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
312
+ border: 2px solid transparent; width: 100%; height: 100%;
313
+ container-type: inline-size; container-name: card;
314
+ }
315
+ /* Hover affordance on resting cards: lift slightly toward the active state so
316
+ the click-to-expand transition reads as continuous. */
317
+ .showcase-card:not(.active) .card-inner:hover {
318
+ opacity: 1; transform: translateY(-2px);
319
+ box-shadow: 0 4px 14px rgba(0,0,0,0.08); border-color: var(--db-border);
320
+ }
321
+ .showcase-card.active .card-inner {
322
+ border-color: var(--db-primary); background-color: #f0f2fd;
323
+ box-shadow: 0 14px 34px rgba(0,0,0,0.15);
324
+ transform: translateX(4px) scale(1.03);
325
+ z-index: 10; opacity: 1;
326
+ }
327
+ .inputElementText { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
328
+ .calc-ro-note { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--db-color-readonly); background: #f8fafc; border: 1px solid var(--db-border); border-radius: 6px; padding: 4px 8px; }
329
+ .calc-ro-note .db-icon { width: 14px; height: 14px; flex: none; }
330
+ .inputElementText .lable { flex: 1; min-width: 0; }
331
+ input, select, textarea {
332
+ box-sizing: border-box; border: 1px solid var(--db-border); background: #fff;
333
+ border-radius: var(--db-radius); padding: 6px 8px; font-family: inherit; font-size: 13px;
334
+ color: var(--db-text); transition: var(--db-transition); width: 100%;
335
+ }
336
+ input:focus, select:focus, textarea:focus { outline: none; border-color: var(--db-primary); box-shadow: 0 0 0 2px rgba(63,81,181,0.1); }
337
+ /* Checkboxes/radios are native controls: don't inherit the text-input box,
338
+ padding, transition or focus ring (which made them grow/shrink on click). */
339
+ input[type="checkbox"], input[type="radio"] {
340
+ width: auto; min-width: 0; padding: 0; margin: 0; border: none; border-radius: 0;
341
+ box-shadow: none; transition: none; flex: none; vertical-align: middle; accent-color: var(--db-primary);
342
+ }
343
+ input[type="checkbox"]:focus, input[type="radio"]:focus { box-shadow: none; }
344
+ select.type { width: auto; flex-shrink: 0; cursor: pointer; }
345
+ .default-value-row { display: flex; align-items: center; gap: 6px; padding: 0 2px 4px; }
346
+ .default-value-row label { font-size: 11px; color: #6b7280; white-space: nowrap; }
347
+ .default-value-row input { flex: 1; min-width: 0; font-size: 12px; padding: 2px 6px; }
348
+
349
+ .card-footer-row { display: flex; flex-direction: column; gap: 8px; }
350
+ .controls-row { display: flex; align-items: center; gap: 6px; }
351
+ /* Once the (floating) card is wide enough, lay the footer out as a single row:
352
+ status buttons on the left, width/copy/delete controls on the right. */
353
+ @container card (min-width: 300px) {
354
+ .card-footer-row { flex-direction: row-reverse; justify-content: space-between; align-items: center; }
355
+ .card-footer-row .controls-row { justify-content: flex-end; flex: 0 0 auto; }
356
+ /* Status buttons take the remaining width and wrap within it, so they break
357
+ before the width/copy/delete controls instead of crowding them. */
358
+ .card-footer-row .card-status-strip { flex: 1 1 auto; min-width: 0; }
359
+ }
360
+ @container card (max-width: 399.9px) {
361
+ .inputElementText { flex-direction: column; align-items: stretch; gap: 8px; }
362
+ .inputElementText select.type { width: 100%; }
363
+ }
364
+ .width-adjust-box {
365
+ display: flex; align-items: center; gap: 2px; background: #fff; border: 1px solid var(--db-border);
366
+ border-radius: 5px; padding: 2px 4px; font-size: 12px;
367
+ }
368
+ .width-adjust-box span { font-weight: 600; color: #64748b; padding: 0 4px; }
369
+ .width-adjust-box .width-value { font-weight: 700; color: var(--db-text); }
370
+ .width-adjust-box button { padding: 2px 6px; margin: 0; background: transparent; color: var(--db-primary); font-size: 13px; font-weight: bold; border: none; border-radius: 4px; cursor: pointer; width: auto; }
371
+ .width-adjust-box button:hover { background-color: rgba(0,0,0,0.05); }
372
+
373
+ .control-btn {
374
+ background: #fff; border: 1px solid var(--db-border); border-radius: 5px; padding: 0; font-size: 11px;
375
+ cursor: pointer; display: inline-flex; align-items: center; justify-content: center; height: 24px;
376
+ min-width: 24px; color: var(--db-text-muted); transition: var(--db-transition); width: auto;
377
+ }
378
+ .control-btn .db-icon { width: 16px; height: 16px; }
379
+ .control-btn:hover { background-color: rgba(0,0,0,0.05); color: var(--db-text); }
380
+ .copy-btn:hover { border-color: var(--db-primary); color: var(--db-primary); }
381
+ .delete-btn:hover { border-color: #ef4444; color: #ef4444; background-color: #fef2f2; }
382
+ .delete-confirm-wrapper { display: inline-flex; gap: 4px; align-items: center; }
383
+ .confirm-yes-btn { background-color: #ef4444; color: #fff; border-color: #ef4444; width: auto; padding: 0 8px; }
384
+ .confirm-yes-btn:hover { background-color: #dc2626; }
385
+ .confirm-no-btn { background-color: #f1f5f9; color: #475569; border-color: #cbd5e1; width: auto; padding: 0 8px; }
386
+
387
+ .card-status-strip { display: flex; flex-wrap: wrap; gap: 4px; }
388
+ .showcase-card:not(.active) .card-status-strip { display: none; }
389
+ .status-btn {
390
+ background: transparent; border: none; padding: 0 8px; margin: 0; cursor: pointer; border-radius: 5px;
391
+ transition: var(--db-transition); display: inline-flex; align-items: center; justify-content: center;
392
+ height: 28px; color: #94a3b8; gap: 4px; font-size: 11px; font-weight: 500; white-space: nowrap; width: auto;
393
+ }
394
+ .status-btn .db-icon { width: 18px; height: 18px; }
395
+ .status-btn:hover { background-color: rgba(0,0,0,0.05); color: var(--db-text); }
396
+ .status-btn.active { background-color: #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.08); border: 1px solid rgba(0,0,0,0.05); }
397
+ .status-btn.active-readonly { color: var(--db-color-readonly); }
398
+ .status-btn.active-hid { color: var(--db-color-hid); }
399
+ .status-btn.active-opt { color: var(--db-color-opt); }
400
+ .status-btn.active-calc { color: var(--db-color-calc); }
401
+ .status-btn.active-color { color: var(--db-color-clr); }
402
+ .status-btn.active-val { color: var(--db-color-val); }
403
+ .status-btn.active-email { color: var(--db-color-email); }
404
+ .status-btn.tab-open { background-color: rgba(63,81,181,0.15); outline: 1px solid var(--db-primary); color: var(--db-primary); }
405
+
406
+ .card-drawer {
407
+ margin-top: 10px; padding: 10px; background: #fff; border: 1px solid var(--db-border);
408
+ border-radius: var(--db-radius); font-size: 12.5px; display: flex; flex-direction: column; gap: 6px;
409
+ }
410
+ .drawer-title { font-weight: 700; color: var(--db-primary); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em; }
411
+
412
+ /* Options editor */
413
+ .format-selector { display: flex; gap: 6px; margin-bottom: 6px; align-items: center; }
414
+ .format-btn { font-size: 10.5px; padding: 3px 8px; background: #f1f5f9; border: 1px solid #cbd5e1; border-radius: 4px; cursor: pointer; font-weight: 500; color: var(--db-text-muted); width: auto; }
415
+ .format-btn.active { background: var(--db-primary); color: #fff; border-color: var(--db-primary); }
416
+ .add-opt-row { display: flex; gap: 4px; margin-top: 6px; align-items: center; }
417
+ .add-opt-row input { flex: 1; }
418
+ .add-opt-btn { background: var(--db-primary); color: #fff; border: none; border-radius: 6px; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; font-size: 16px; cursor: pointer; flex-shrink: 0; }
419
+ .add-opt-btn:hover { background-color: var(--db-primary-hover); }
420
+ .options-table { width: 100%; border-collapse: collapse; margin: 4px 0; }
421
+ .options-table th, .options-table td { border: 1px solid #e2e8f0; padding: 4px; font-size: 11px; }
422
+ .options-table th { background: #f8fafc; font-weight: 600; text-align: left; }
423
+ .opt-string-row { display: flex; gap: 4px; margin-bottom: 4px; }
424
+ .opt-del { padding: 2px 6px; font-size: 10px; margin: 0; background: #ffebee; color: red; cursor: pointer; border: none; border-radius: 3px; width: auto; }
425
+
426
+ /* Add buttons */
427
+ .add-card-placeholder { display: block; cursor: pointer; height: 100%; min-height: 52px; width: 36px; }
428
+ .add-card-inner { border: 2px dashed #cbd5e1; border-radius: var(--db-radius); height: 100%; display: flex; align-items: center; justify-content: center; color: #64748b; transition: var(--db-transition); min-height: 52px; }
429
+ .add-card-placeholder:hover .add-card-inner { border-color: var(--db-primary); color: var(--db-primary); }
430
+ .add-row-btn {
431
+ width: 100%; height: 36px; border: 2px dashed #cbd5e1; border-radius: 8px; background: transparent;
432
+ color: #64748b; font-size: 13px; font-weight: 600; cursor: pointer; display: flex; align-items: center;
433
+ justify-content: center; gap: 8px; transition: var(--db-transition); margin-bottom: 24px;
434
+ }
435
+ .add-row-btn:hover { border-color: var(--db-primary); color: var(--db-primary); }
436
+
437
+ /* Rule builder */
438
+ .rb-host { display: block; }
439
+ .rb-rule { border: 1px solid var(--db-border); border-radius: 8px; background: #fbfbfd; padding: 8px; margin-bottom: 8px; }
440
+ .rb-head { display: flex; align-items: center; gap: 4px; margin-bottom: 6px; }
441
+ .rb-idx { font-size: 10px; font-weight: 700; color: #fff; background: var(--db-primary); border-radius: 999px; padding: 1px 8px; }
442
+ .rb-idx.calc { background: var(--db-color-calc); }
443
+ .rb-idx.color { background: var(--db-color-clr); }
444
+ .rb-idx.readonly { background: var(--db-color-readonly); }
445
+ .rb-idx.hidden { background: var(--db-color-hid); }
446
+ .rb-spacer { flex: 1; }
447
+ .rb-kw { font-size: 10px; font-weight: 700; color: var(--db-primary); letter-spacing: 0.04em; }
448
+ .rb-kw.then { color: var(--db-color-val); }
449
+ .rb-cond { border: 1px solid #eef0f4; border-radius: 6px; padding: 6px; margin: 4px 0; background: #fff; }
450
+ .rb-cond .row1 { margin-bottom: 4px; }
451
+ .rb-cond .row2 { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
452
+ .rb-cond select, .rb-cond input { font-size: 11px; padding: 4px 5px; }
453
+ .rb-cond .f { width: 100%; }
454
+ .rb-cond .op { flex: 1.1; min-width: 0; }
455
+ .rb-cond .val { flex: 1; min-width: 0; }
456
+ .rb-rhsmode { display: inline-flex; border: 1px solid var(--db-border); border-radius: 5px; overflow: hidden; flex-shrink: 0; }
457
+ .rb-rhsmode button { border: none; background: #fff; font-size: 9.5px; font-weight: 700; padding: 4px 6px; cursor: pointer; color: var(--db-text-muted); width: auto; }
458
+ .rb-rhsmode button.on { background: var(--db-primary); color: #fff; }
459
+ .rb-x { background: transparent; border: none; color: #c0c4cf; cursor: pointer; font-size: 11px; flex-shrink: 0; padding: 2px 4px; width: auto; }
460
+ .rb-x:hover { color: #c0392b; }
461
+ .rb-combo { display: inline-flex; border: 1px solid var(--db-border); border-radius: 5px; overflow: hidden; margin: 2px 0 4px; }
462
+ .rb-combo button { border: none; background: #fff; font-size: 10px; font-weight: 700; padding: 2px 9px; cursor: pointer; color: var(--db-text-muted); width: auto; }
463
+ .rb-combo button.on { background: var(--db-primary); color: #fff; }
464
+ .rb-add { font-size: 10.5px; color: var(--db-primary); background: #fff; border: 1px dashed var(--db-border); border-radius: 5px; padding: 3px 9px; cursor: pointer; margin-top: 2px; width: auto; }
465
+ .rb-add:hover { background: rgba(63,81,181,0.08); border-color: var(--db-primary); }
466
+ .rb-addrule { width: 100%; padding: 7px; font-size: 11.5px; font-weight: 600; color: var(--db-primary); background: #fff; border: 1px dashed var(--db-primary); border-radius: 6px; cursor: pointer; }
467
+ .rb-addrule:hover { background: rgba(63,81,181,0.08); }
468
+ .rb-msg { width: 100%; font-size: 11px; padding: 5px; }
469
+ .calc-trigger { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
470
+ .calc-trigger-label { font-size: 10px; font-weight: 700; color: var(--db-text-muted); text-transform: uppercase; letter-spacing: 0.04em; }
471
+ .rb-else { border: 1px solid var(--db-color-calc); background: #e3f3f3; border-radius: 8px; padding: 8px; margin-top: 8px; }
472
+ .rb-vrow { display: flex; gap: 4px; align-items: flex-start; }
473
+ .rb-vrow select.k { width: 92px; flex-shrink: 0; font-size: 11px; padding: 4px; }
474
+ .rb-vrow .vb { flex: 1; min-width: 0; }
475
+ .rb-vrow .vb input, .rb-vrow .vb select, .rb-vrow .vb textarea { width: 100%; font-size: 11px; padding: 4px 5px; }
476
+ .rb-jsonerr { font-size: 10px; color: #c0392b; margin-top: 2px; }
477
+ /* Color-rule swatch palette: round, selectable color buttons. */
478
+ .rb-swatches { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
479
+ .rb-swatch {
480
+ width: 22px; height: 22px; border-radius: 50%; padding: 0; cursor: pointer;
481
+ border: 2px solid #fff; box-shadow: 0 0 0 1px var(--db-border); transition: var(--db-transition);
482
+ display: inline-flex; align-items: center; justify-content: center;
483
+ }
484
+ .rb-swatch:hover { transform: scale(1.12); }
485
+ .rb-swatch.sel { box-shadow: 0 0 0 2px var(--db-text); }
486
+ .rb-swatch.none { background: #fff; color: var(--db-text-muted); }
487
+ .rb-swatch.none .db-icon { width: 12px; height: 12px; }
488
+
489
+ /* Email-on-change editor */
490
+ .email-hint { font-size: 11px; color: var(--db-text-muted); margin-bottom: 4px; }
491
+ .email-rule { border: 1px solid var(--db-border); border-radius: 8px; background: #fbfbfd; padding: 8px; margin-bottom: 8px; }
492
+ .email-head { display: flex; align-items: center; gap: 4px; margin-bottom: 6px; }
493
+ .email-idx { font-size: 10px; font-weight: 700; color: #fff; background: var(--db-color-email); border-radius: 999px; padding: 1px 8px; }
494
+ .email-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-top: 6px; }
495
+ .email-kw { font-size: 10px; font-weight: 700; color: var(--db-text-muted); letter-spacing: 0.04em; }
496
+ .email-row .email-val { flex: 1; min-width: 90px; font-size: 11px; padding: 4px 5px; }
497
+ .email-note { font-size: 11px; color: var(--db-text-muted); font-style: italic; }
498
+ .email-cond { border: 1px solid #eef0f4; border-radius: 6px; padding: 6px; margin: 4px 0; background: #fff; }
499
+ .email-cond-r1 { margin-bottom: 4px; }
500
+ .email-cond-r2 { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
501
+ .email-cond .email-val { flex: 1; min-width: 0; font-size: 11px; padding: 4px 5px; }
502
+ .email-cond .email-kind { flex: 0 0 auto; font-size: 11px; padding: 4px 5px; }
503
+ .email-cond .email-cond-r1 .email-val { width: 100%; }
504
+ .email-and { display: inline-flex; font-size: 10px; font-weight: 700; color: var(--db-text-muted); padding: 2px 0; }
505
+ .rb-plain { font-size: 11.5px; margin-top: 8px; background: #eef2ff; color: var(--db-text); border: 1px solid #d6deff; border-left: 3px solid var(--db-primary); padding: 7px 9px; border-radius: 6px; line-height: 1.55; }
506
+ .rb-plain-label { font-size: 9px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--db-primary); font-weight: 700; display: block; margin-bottom: 3px; }
507
+
508
+ .drawer-roles-section { margin-bottom: 12px; padding: 8px 12px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; }
509
+ .drawer-roles-title { font-size: 11px; font-weight: 700; text-transform: uppercase; color: #64748b; margin-bottom: 6px; letter-spacing: 0.05em; }
510
+ .drawer-roles-list { display: flex; flex-wrap: wrap; gap: 12px; }
511
+ .drawer-role-item { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #334155; cursor: pointer; font-weight: 500; }
512
+ .drawer-role-item input { width: auto; margin: 0; cursor: pointer; }
513
+
514
+ /* Formula editor */
515
+ .formula-editor-container { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 10px; width: 100%; }
516
+ .formula-preview-label, .formula-field-pills-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: #64748b; margin-bottom: -4px; }
517
+ .formula-preview { background: #0f172a; color: #f8fafc; padding: 10px 12px; border-radius: 6px; font-family: 'Fira Code', monospace; font-size: 12px; min-height: 20px; white-space: pre-wrap; word-break: break-all; }
518
+ .formula-preview .hl-field { background: rgba(14,165,233,0.2); color: #38bdf8; border: 1px solid rgba(56,189,248,0.4); padding: 0 4px; border-radius: 3px; }
519
+ .formula-preview .hl-func { color: #f472b6; font-weight: 700; }
520
+ .formula-preview .hl-op { color: #a78bfa; font-weight: 600; }
521
+ .formula-preview .hl-num { color: #34d399; }
522
+ .formula-preview .hl-str { color: #fbbf24; font-style: italic; }
523
+ .formula-preview .hl-word { color: #e2e8f0; }
524
+ .formula-preview .hl-empty { color: #64748b; font-style: italic; }
525
+ .formula-input-field { font-family: 'Fira Code', monospace; font-size: 13px; padding: 8px 10px; border: 1px solid #cbd5e1; border-radius: 6px; width: 100%; }
526
+ .formula-toolbar { display: flex; flex-wrap: wrap; gap: 4px; background: #f1f5f9; padding: 6px; border-radius: 6px; border: 1px solid #e2e8f0; }
527
+ .formula-tool-btn { background: #fff; border: 1px solid #cbd5e1; border-radius: 4px; padding: 3px 8px; font-family: 'Fira Code', monospace; font-size: 11px; font-weight: 600; color: #334155; cursor: pointer; width: auto; }
528
+ .formula-tool-btn:hover { background: #e2e8f0; }
529
+ .formula-tool-btn.func { background: #eef2ff; border-color: #c7d2fe; color: var(--db-primary); }
530
+ .formula-field-pills { display: flex; flex-wrap: wrap; gap: 6px; max-height: 120px; overflow-y: auto; padding: 2px; }
531
+ .formula-field-pill { background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 4px 10px; font-size: 11px; font-weight: 500; color: #475569; cursor: pointer; width: auto; }
532
+ .formula-field-pill:hover { background: #e0f2fe; border-color: #7dd3fc; color: #0369a1; }
533
+ .formula-guide { display: flex; gap: 8px; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 6px; padding: 8px 10px; font-size: 11px; color: #1e3a8a; line-height: 1.4; }
534
+ .formula-guide code { background: rgba(29,78,216,0.1); padding: 1px 3px; border-radius: 3px; font-family: 'Fira Code', monospace; font-weight: 600; }
535
+
536
+ /* Debug / export */
537
+ .debug-header { display: flex; justify-content: space-between; align-items: center; width: 100%; margin-top: 24px; margin-bottom: 12px; gap: 8px; flex-wrap: wrap; }
538
+ .debug-tab-btn { background: transparent; border: 1px solid var(--db-border); color: var(--db-text-muted); padding: 6px 12px; border-radius: 6px; font-size: 13px; font-weight: 600; cursor: pointer; width: auto; }
539
+ .debug-tab-btn.active { background: var(--db-primary); border-color: var(--db-primary); color: #fff; }
540
+ .debug-tab-btn:hover:not(.active) { background: #f1f5f9; color: var(--db-text); }
541
+ .debug-panel { background: #fff; border: 1px solid var(--db-border); border-radius: var(--db-radius); padding: 12px; font-family: monospace; font-size: 11.5px; white-space: pre-wrap; width: 100%; overflow-x: auto; }
542
+ .debug-edit-bar { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-bottom: 8px; }
543
+ .debug-edit-err { color: #dc2626; font-family: 'Inter', system-ui, sans-serif; font-size: 12px; }
544
+ .debug-edit-area { width: 100%; min-height: 320px; resize: vertical; border: 1px solid var(--db-border); border-radius: 6px; padding: 10px; font-family: monospace; font-size: 11.5px; line-height: 1.45; color: var(--db-text); box-sizing: border-box; }
545
+ .debug-edit-area:focus { outline: none; border-color: var(--db-primary); }
546
+ `;var D=Object.freeze({READONLY:"readonly",HIDDEN:"hidden",OPTIONS:"options",MULTIPLE:"multiple",CALCULATION:"calculation",COLOR:"color",VALIDATION:"validation",EMAIL:"email",DEFAULT:"default"}),w=D,X=[{value:"text",label:"Text",icon:"short_text",defaultWidth:2,features:[w.READONLY,w.HIDDEN,w.OPTIONS,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"text"},{value:"number",label:"Number",icon:"tag",defaultWidth:2,features:[w.READONLY,w.HIDDEN,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"number"},{value:"dropdown",label:"Select",icon:"list",defaultWidth:2,features:[w.READONLY,w.HIDDEN,w.OPTIONS,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"text"},{value:"dropdownList",label:"Select (Multi)",icon:"checklist",defaultWidth:2,features:[w.READONLY,w.HIDDEN,w.OPTIONS,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"array",multiple:!0},{value:"textarea",label:"Textarea",icon:"notes",defaultWidth:3,features:[w.READONLY,w.HIDDEN,w.CALCULATION,w.COLOR,w.VALIDATION,w.DEFAULT],valueBucket:"text"},{value:"checkbox",label:"Checkbox",icon:"check_box",defaultWidth:1,features:[w.READONLY,w.HIDDEN,w.CALCULATION,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"bool"},{value:"date",label:"Date",icon:"calendar_today",defaultWidth:2,features:[w.READONLY,w.HIDDEN,w.CALCULATION,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"text"},{value:"radioCards",label:"Radio Cards",icon:"radio_button_checked",defaultWidth:3,features:[w.READONLY,w.HIDDEN,w.OPTIONS,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"text"},{value:"radioCardsMulti",label:"Radio Cards (Multi)",icon:"check_box",defaultWidth:3,features:[w.READONLY,w.HIDDEN,w.OPTIONS,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"array",multiple:!0},{value:"richText",label:"Rich Text",icon:"edit_note",defaultWidth:4,features:[w.READONLY,w.HIDDEN,w.VALIDATION,w.DEFAULT],valueBucket:"text"},{value:"toggle",label:"Toggle",icon:"toggle_on",defaultWidth:1,features:[w.READONLY,w.HIDDEN,w.CALCULATION,w.COLOR,w.VALIDATION,w.EMAIL,w.DEFAULT],valueBucket:"bool"},{value:"comments",label:"Comments",icon:"comment",defaultWidth:4,features:[w.READONLY,w.HIDDEN,w.VALIDATION,w.DEFAULT],valueBucket:"text"},{value:"empty",label:"Empty Spacer",icon:"crop_free",defaultWidth:2,features:[w.HIDDEN],valueBucket:"text"},{value:"label",label:"Label",icon:"label",defaultWidth:2,features:[w.HIDDEN,w.COLOR],valueBucket:"text"},{value:"description",label:"Description",icon:"subject",defaultWidth:4,features:[w.HIDDEN,w.COLOR],valueBucket:"text"},{value:"appendicesLink",label:"Appendices Link",icon:"link",defaultWidth:2,features:[w.READONLY,w.HIDDEN],valueBucket:"text"}];function Q(o=X){let e=Array.isArray(o)?o:Object.values(o),t=new Map;if(e.forEach(i=>{if(!i||typeof i.value!="string")throw new Error('[dialog-builder] Each field type needs a string "value".');t.set(i.value,{value:i.value,label:i.label||i.value,icon:i.icon||"widgets",defaultWidth:Number.isFinite(i.defaultWidth)?i.defaultWidth:2,features:Array.isArray(i.features)?i.features.slice():[],valueBucket:i.valueBucket||"text",multiple:!!i.multiple})}),t.size===0)throw new Error("[dialog-builder] Field-type registry cannot be empty.");return t}function at(o,e,t){let i=o.get(e);return!!(i&&i.features.includes(t))}var je={};rt(je,{RB_COLORS:()=>U,RB_NUMERIC_OPS:()=>B,RB_OPERATORS:()=>L,RB_VALUE_KINDS:()=>he,compileFormulaToJs:()=>ze,encodeMessage:()=>qe,fieldRef:()=>te,genBoolJs:()=>I,genCalculationJs:()=>z,genColorJs:()=>q,genEmailJs:()=>oe,genPlain:()=>me,genValidationJs:()=>M,highlightFormula:()=>dt,jsAttr:()=>A,operatorsFor:()=>W,propByKey:()=>P,rbEsc:()=>m,rbGenValue:()=>fe,sanitizeMessage:()=>ne,wire:()=>st});function m(o){return String(o).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function A(o){return String(o).replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}function st(o,e,t=[],i=""){let n=`data-${o}="${e}"`;return t&&t.length&&(n+=` data-args="${m(JSON.stringify(t))}"`),i&&(n+=` data-arg-${i}`),n}function te(o){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(o)?`x.${o}`:`x[${JSON.stringify(o)}]`}function P(o,e){return o.find(t=>t.key===e)}var L={isEmpty:{label:"is empty",needsValue:!1,types:"all",gen:o=>`(${o} === null || ${o} === undefined || ${o} === "")`},isNotEmpty:{label:"is not empty",needsValue:!1,types:"all",gen:o=>`(${o} !== null && ${o} !== undefined && ${o} !== "")`},equals:{label:"equals",needsValue:!0,types:"all",gen:(o,e)=>`${o} === ${e}`},notEquals:{label:"does not equal",needsValue:!0,types:"all",gen:(o,e)=>`${o} !== ${e}`},contains:{label:"contains text",needsValue:!0,types:"text",gen:(o,e)=>`String(${o} ?? "").includes(${e})`},greaterThan:{label:"is greater than",needsValue:!0,types:"number",gen:(o,e)=>`Number(${o}) > ${e}`},lessThan:{label:"is less than",needsValue:!0,types:"number",gen:(o,e)=>`Number(${o}) < ${e}`},isChecked:{label:"is checked (true)",needsValue:!1,types:"bool",gen:o=>`${o} === true`},isNotChecked:{label:"is not checked",needsValue:!1,types:"bool",gen:o=>`${o} !== true`},matchesRegex:{label:"matches pattern",needsValue:!0,types:"text",gen:(o,e)=>`new RegExp(${e}).test(String(${o} ?? ""))`},hasNoItems:{label:"has no items",needsValue:!1,types:"array",gen:o=>`(${o} == null || ${o}.length === 0)`},hasAnyItems:{label:"has any items",needsValue:!1,types:"array",gen:o=>`(${o} != null && ${o}.length > 0)`},itemCountEquals:{label:"item count equals",needsValue:!0,types:"array",gen:(o,e)=>`(${o}?.length ?? 0) === ${e}`},itemCountAtLeast:{label:"item count is at least",needsValue:!0,types:"array",gen:(o,e)=>`(${o}?.length ?? 0) >= ${e}`},itemCountMoreThan:{label:"item count is more than",needsValue:!0,types:"array",gen:(o,e)=>`(${o}?.length ?? 0) > ${e}`},arrayContains:{label:"contains item",needsValue:!0,types:"array",gen:(o,e)=>`(Array.isArray(${o}) && ${o}.includes(${e}))`}},B=["greaterThan","lessThan","itemCountEquals","itemCountAtLeast","itemCountMoreThan"],U=["#3f51b5","#fea20f","#0fa216","#f44336","#9c27b0","#00bcd4","#e91e63","#795548","#607d8b"],he=[["number","Number"],["string","Text"],["boolean","True/False"],["date","Date"],["expression","Formula"],["field","Field"],["object","JSON"]];function lt(o){return o?o.valueBucket?o.valueBucket:o.type==="number"?"number":o.type==="checkbox"?"bool":o.multiple||["array","linkedObjects","dropdownList","comments"].includes(o.type)?"array":"text":"text"}function W(o,e){if(e==="currentUserRole"||e==="currentUser")return["equals","notEquals"];let t=lt(P(o,e));return t==="array"?Object.keys(L).filter(i=>L[i].types==="array"):Object.keys(L).filter(i=>L[i].types==="all"||L[i].types===t)}function ze(o,e){if(!o)return"null";let t=o;return t=t.replace(/==/g,"="),t=t.replace(/>=/g,"__GTE__"),t=t.replace(/<=/g,"__LTE__"),t=t.replace(/<>/g,"__NE__"),t=t.replace(/!=/g,"__NE__"),t=t.replace(/=/g,"=== "),t=t.replace(/__GTE__/g,">="),t=t.replace(/__LTE__/g,"<="),t=t.replace(/__NE__/g,"!=="),t=t.replace(/\^/g,"**"),[...e].sort((n,r)=>{let a=Math.max((n.label||"").length,(n.key||"").length);return Math.max((r.label||"").length,(r.key||"").length)-a}).forEach(n=>{let r=`[${n.label}]`,a=`[${n.key}]`,l;n.type==="number"?l=`((x.${n.key} != null && x.${n.key} !== "") ? Number(x.${n.key}) : null)`:n.type==="checkbox"?l=`(x.${n.key} === true)`:l=`((x.${n.key} != null && x.${n.key} !== "") ? x.${n.key} : null)`,n.label&&(t=t.split(r).join(l)),n.key&&(t=t.split(a).join(l))}),t}function dt(o,e){if(!o)return'<span class="hl-empty">No formula entered</span>';let t=s=>s.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),i=[];e.forEach(s=>{s.label&&i.push(t(s.label)),s.key&&i.push(t(s.key))}),i.sort((s,b)=>b.length-s.length);let n=i.length?"(\\[(?:"+i.join("|")+")\\])":"(\\[[^\\]]+\\])",r=new RegExp(n+`|("[^"]*")|('[^']*')|([A-Za-z_][A-Za-z0-9_]*)|(\\d+(?:\\.\\d+)?)|([\\+\\-\\*\\/\\^=<>!\\?]+)|(\\s+)|(.)`,"g"),a,l="";for(;(a=r.exec(o))!==null;){let[s,b,h,v,g,R,d,p]=a;if(b)l+=`<span class="hl-field">${m(s)}</span>`;else if(h||v)l+=`<span class="hl-str">${m(s)}</span>`;else if(g){let f=["IF","SUM","AVERAGE","MIN","MAX","ROUND","AND","OR","NOT","AVG"].includes(g.toUpperCase());l+=f?`<span class="hl-func">${m(g)}</span>`:`<span class="hl-word">${m(g)}</span>`}else R?l+=`<span class="hl-num">${m(s)}</span>`:d?l+=`<span class="hl-op">${m(s)}</span>`:p?l+=s:l+=m(s)}return l}function ct(o,e,t,i){let n=P(o,e);if(B.includes(t)||n&&n.type==="number"&&(t==="equals"||t==="notEquals")){let a=Number(i);return Number.isFinite(a)?String(a):"0"}return JSON.stringify(String(i??""))}function ut(o,e){if(e.valueMode==="field"){let t=e.valueField?te(e.valueField):"undefined";return B.includes(e.operator)?`Number(${t})`:t}return ct(o,e.field,e.operator,e.value)}function pt(o,e){let t=L[e.operator];if(!t||!e.field)return"false";let i=te(e.field);return t.needsValue?t.gen(i,ut(o,e)):t.gen(i)}function ie(o,e){let t=(e.conditions||[]).filter(r=>r.field);if(!t.length)return null;let i=t.map(r=>pt(o,r)),n=e.combinator==="OR"?" || ":" && ";return i.length>1?"("+i.join(n)+")":i[0]}function fe(o,e){if(!e)return"null";switch(e.kind){case"number":{let t=Number(e.value);return Number.isFinite(t)?String(t):"0"}case"string":return JSON.stringify(String(e.value??""));case"boolean":return e.value===!0||e.value==="true"?"true":"false";case"date":{let t=e.dateType||"today";if(t==="today")return"new Date()";if(t==="firstOfMonth")return"new Date(new Date().getFullYear(), new Date().getMonth(), 1)";if(t==="relative"){let i=e.relativeField||o[0]&&o[0].key||"",n=e.relativeDays!==void 0?Number(e.relativeDays):0;return`((x.${i} != null && x.${i} !== "") ? new Date(new Date(x.${i}).getTime() + (${n} * 24 * 60 * 60 * 1000)) : null)`}return"null"}case"field":return e.field?te(e.field):"null";case"object":try{return JSON.stringify(JSON.parse(e.value))}catch{return"null /* invalid JSON */"}case"expression":return e.value&&e.value.trim()?`ROUND(${ze(e.value,o)}, ${e.decimals!==void 0?Number(e.decimals):2})`:"null";default:return"null"}}function ne(o){return String(o??"").replace(/[\r\n\t]+/g," ").trim()}function qe(o){return JSON.stringify(ne(o))}function ge(o,e){return o.map(t=>`${t.cond} ? ${t.val} : `).join("")+e}function M(o,e){let t=[];return(e.rules||[]).forEach(i=>{let n=ie(o,i.when);n&&t.push({cond:n,val:qe(i.message)})}),t.length?`x => ${ge(t,'""')}`:'x => ""'}function z(o,e){let t=[];(e.rules||[]).forEach(r=>{let a=ie(o,r.when);a&&t.push({cond:a,val:fe(o,r.result)})});let i=ge(t,fe(o,e.else));return i.includes("ROUND(")?`x => {
547
+ const ROUND = (v, p = 2) => { const factor = Math.pow(10, p); return Math.round(Number(v || 0) * factor) / factor; };
548
+ return ${i};
549
+ }`:`x => ${i}`}function q(o,e){let t=[];return(e.rules||[]).forEach(i=>{let n=ie(o,i.when);n&&i.color&&t.push({cond:n,val:JSON.stringify(i.color)})}),t.length?`x => ${ge(t,'""')}`:'x => ""'}function be(o,e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)?`${o}.${e}`:`${o}[${JSON.stringify(e)}]`}function ft(o){if(!o||!o.field)return null;let e=JSON.stringify(String(o.value??"")),t=be("x",o.field),i=be("prevX",o.field);return o.kind==="changedFrom"?`${i} === ${e}`:o.kind==="is"?`${t} === ${e}`:`(${t} === ${e} && ${i} !== ${t})`}function oe(o,e){let t=(e||[]).filter(n=>n&&(n.recipientType==="role"?n.role:n.field)&&Array.isArray(n.conditions)&&n.conditions.some(r=>r.field));return t.length?`(prevX, x) => {
550
+ const recipients = [];
551
+ ${t.map(n=>{let r=n.conditions.map(ft).filter(Boolean),a=r.length?r.join(" && "):"false",l=n.recipientType==="role"?`{ type: "role", role: ${JSON.stringify(n.role)} }`:`{ type: "field", field: ${JSON.stringify(n.field)}, value: ${be("x",n.field)} }`;return` if (${a}) recipients.push(${l});`}).join(`
552
+ `)}
553
+ return recipients;
554
+ }`:""}function I(o,e,t,i){let n=[];return i&&i.length===1?n.push(`x.currentUserRole === ${JSON.stringify(i[0])}`):i&&i.length>1&&n.push(`${JSON.stringify(i)}.includes(x.currentUserRole)`),(e&&e.rules?e.rules:[]).forEach(a=>{let l=ie(o,a.when);l&&n.push(l)}),n.length?`x => ${n.join(" || ")}`:`x => ${t}`}function ee(o,e){let t=P(o,e);return t?t.label:e}function bt(o,e){let t=L[e.operator];if(!t||!e.field)return"\u2026";let i=ee(o,e.field);if(!t.needsValue)return`${i} ${t.label}`;let n=e.valueMode==="field"?e.valueField?`the value of ${ee(o,e.valueField)}`:"another field":`\u201C${e.value??""}\u201D`;return`${i} ${t.label} ${n}`}function J(o,e){let t=(e.conditions||[]).filter(n=>n.field);if(!t.length)return"";let i=e.combinator==="OR"?" or ":" and ";return t.map(n=>bt(o,n)).join(i)}function pe(o,e){if(!e)return"nothing";switch(e.kind){case"number":{let t=Number(e.value);return`the number ${Number.isFinite(t)?t:0}`}case"string":return e.value?`the text \u201C${e.value}\u201D`:"empty text";case"boolean":return e.value===!0||e.value==="true"?"true":"false";case"date":{let t=e.dateType||"today";if(t==="today")return"today's date";if(t==="firstOfMonth")return"the first day of the current month";if(t==="relative"){let i=ee(o,e.relativeField||""),n=e.relativeDays!==void 0?Number(e.relativeDays):0;return`${Math.abs(n)} day(s) ${n>=0?"after":"before"} the date of ${i}`}return"nothing"}case"field":return e.field?`the value of ${ee(o,e.field)}`:"nothing";case"object":return"a JSON object";case"expression":return e.value&&e.value.trim()?`the formula ${e.value.trim()}`:"nothing";default:return"nothing"}}function me(o,e,t,i){let n=t.rules||[],r=[],a=i&&i.length>0?`for roles: ${i.join(", ")}`:"";return e==="validation"?(n.forEach(l=>{let s=J(o,l.when);s&&r.push(`If ${s}, show the message \u201C${l.message||""}\u201D.`)}),r.length?r.join(" "):"This field is always valid."):e==="readonly"?(a&&r.push(`Make this field read-only ${a}.`),n.forEach(l=>{let s=J(o,l.when);s&&r.push(`Make this field read-only when ${s}.`)}),r.length?r.join(" "):"This field is always editable."):e==="hidden"?(a&&r.push(`Hide this field ${a}.`),n.forEach(l=>{let s=J(o,l.when);s&&r.push(`Hide this field when ${s}.`)}),r.length?r.join(" "):"This field is always visible."):e==="color"?(n.forEach(l=>{let s=J(o,l.when);s&&l.color&&r.push(`Use the color ${l.color} when ${s}.`)}),r.length?r.join(" "):"No color set."):(n.forEach(l=>{let s=J(o,l.when);s&&r.push(`Use ${pe(o,l.result)} when ${s}.`)}),r.length?(r.push(`Otherwise use ${pe(o,t.else)}.`),r.join(" ")):`Set this field to ${pe(o,t.else)}.`)}var ve={add:"M440-440H200v-80h240v-240h80v240h240v80H520v240h-80v-240Z",close:"m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z",content_copy:"M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z",data_object:"M560-160v-80h120q17 0 28.5-11.5T720-280v-80q0-38 22-69t58-44v-14q-36-13-58-44t-22-69v-80q0-17-11.5-28.5T680-720H560v-80h120q50 0 85 35t35 85v80q0 17 11.5 28.5T840-560h40v160h-40q-17 0-28.5 11.5T800-360v80q0 50-35 85t-85 35H560Zm-280 0q-50 0-85-35t-35-85v-80q0-17-11.5-28.5T120-400H80v-160h40q17 0 28.5-11.5T160-600v-80q0-50 35-85t85-35h120v80H280q-17 0-28.5 11.5T240-680v80q0 38-22 69t-58 44v14q36 13 58 44t22 69v80q0 17 11.5 28.5T280-240h120v80H280Z",delete:"M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z",lock:"M240-80q-33 0-56.5-23.5T160-160v-400q0-33 23.5-56.5T240-640h40v-80q0-83 58.5-141.5T480-920q83 0 141.5 58.5T680-720v80h40q33 0 56.5 23.5T800-560v400q0 33-23.5 56.5T720-80H240Zm0-80h480v-400H240v400Zm240-120q33 0 56.5-23.5T560-360q0-33-23.5-56.5T480-440q-33 0-56.5 23.5T400-360q0 33 23.5 56.5T480-280ZM360-640h240v-80q0-50-35-85t-85-35q-50 0-85 35t-35 85v80ZM240-160v-400 400Z",visibility_off:"m644-428-58-58q9-47-27-88t-93-32l-58-58q17-8 34.5-12t37.5-4q75 0 127.5 52.5T660-500q0 20-4 37.5T644-428Zm128 126-58-56q38-29 67.5-63.5T832-500q-50-101-143.5-160.5T480-720q-29 0-57 4t-55 12l-62-62q41-17 84-25.5t90-8.5q151 0 269 83.5T920-500q-23 59-60.5 109.5T772-302Zm20 246L624-222q-35 11-70.5 16.5T480-200q-151 0-269-83.5T40-500q21-53 53-98.5t73-81.5L56-792l56-56 736 736-56 56ZM222-624q-29 26-53 57t-41 67q50 101 143.5 160.5T480-280q20 0 39-2.5t39-5.5l-36-38q-11 3-21 4.5t-21 1.5q-75 0-127.5-52.5T300-500q0-11 1.5-21t4.5-21l-84-82Zm319 93Zm-151 75Z",list:"M280-600v-80h560v80H280Zm0 160v-80h560v80H280Zm0 160v-80h560v80H280ZM160-600q-17 0-28.5-11.5T120-640q0-17 11.5-28.5T160-680q17 0 28.5 11.5T200-640q0 17-11.5 28.5T160-600Zm0 160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520q17 0 28.5 11.5T200-480q0 17-11.5 28.5T160-440Zm0 160q-17 0-28.5-11.5T120-320q0-17 11.5-28.5T160-360q17 0 28.5 11.5T200-320q0 17-11.5 28.5T160-280Z",calculate:"M320-240h60v-80h80v-60h-80v-80h-60v80h-80v60h80v80Zm200-30h200v-60H520v60Zm0-100h200v-60H520v60Zm44-152 56-56 56 56 42-42-56-58 56-56-42-42-56 56-56-56-42 42 56 56-56 58 42 42Zm-314-70h200v-60H250v60Zm-50 472q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z",bolt:"m422-232 207-248H469l29-227-185 267h139l-30 208ZM320-80l40-280H160l360-520h80l-40 320h240L400-80h-80Zm151-390Z",short_text:"M160-360v-80h400v80H160Zm0-160v-80h640v80H160Z",tag:"m240-160 40-160H120l20-80h160l40-160H180l20-80h160l40-160h80l-40 160h160l40-160h80l-40 160h160l-20 80H660l-40 160h160l-20 80H600l-40 160h-80l40-160H360l-40 160h-80Zm140-240h160l40-160H420l-40 160Z",notes:"M120-240v-80h480v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z",check_box:"m424-312 282-282-56-56-226 226-114-114-56 56 170 170ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z",calendar_today:"M200-80q-33 0-56.5-23.5T120-160v-560q0-33 23.5-56.5T200-800h40v-80h80v80h320v-80h80v80h40q33 0 56.5 23.5T840-720v560q0 33-23.5 56.5T760-80H200Zm0-80h560v-400H200v400Zm0-480h560v-80H200v80Zm0 0v-80 80Z",upload_file:"M440-200h80v-167l64 64 56-57-160-160-160 160 57 56 63-63v167ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z",widgets:"M666-440 440-666l226-226 226 226-226 226Zm-546-80v-320h320v320H120Zm400 400v-320h320v320H520Zm-400 0v-320h320v320H120Zm80-480h160v-160H200v160Zm467 48 113-113-113-113-113 113 113 113Zm-67 352h160v-160H600v160Zm-400 0h160v-160H200v160Zm160-400Zm194-65ZM360-360Zm240 0Z",drag_indicator:"M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z",palette:"M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 32.5-156T201-763q56-54 130-85.5T487-880q80 0 151 27.5t112.5 76q48.5 48.5 76 114T854-526q0 95-64.5 156.5T650-300h-74q-9 0-12.5 5t-3.5 11q0 12 15 34.5t15 51.5q0 50-27.5 83.5T480-80Zm-220-400q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm120-160q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm200 0q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17Zm120 160q26 0 43-17t17-43q0-26-17-43t-43-17q-26 0-43 17t-17 43q0 26 17 43t43 17ZM480-160q11 0 15.5-4.5T500-184q0-14-15-33t-15-57q0-42 29-71t71-29h80q60 0 102-40.5t42-111.5q0-128-94-208t-222-80q-145 0-242.5 96.5T160-480q0 134 93 227t227 93Z",mail:"M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z",save:"M840-680v480q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h480l160 160Zm-80 34L646-760H200v560h560v-446ZM480-240q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35ZM240-560h360v-160H240v160Zm-40-86v446-560 114Z",play_arrow:"M320-200v-560l440 280-440 280Zm80-280Zm0 134 210-134-210-134v268Z",download:"M480-320 280-520l56-58 104 104v-326h80v326l104-104 56 58-200 200ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T800-160H240Z",upload:"M440-200h80v-326l104 104 56-58-200-200-200 200 56 58 104-104v326ZM240-160q-33 0-56.5-23.5T160-240v-120h80v120h480v-120h80v120q0 33-23.5 56.5T800-160H240Z"},ht="widgets";function S(o,e={}){let t=ve[o]||ve[ht],i=e.size!=null?typeof e.size=="number"?`${e.size}px`:e.size:"1em",n=`db-icon${e.cls?" "+e.cls:""}`,r=e.style?` style="${e.style}"`:"";return`<svg class="${n}" width="${i}" height="${i}" viewBox="0 -960 960 960" fill="currentColor" aria-hidden="true" focusable="false"${r}><path d="${t}"></path></svg>`}var gt={validation:"val",calculation:"cal",readonly:"ro",hidden:"hid",color:"col"},mt={validation:"val",readonly:"ro",hidden:"hid",calculation:"cal",color:"col"};function Ve(o){let e=()=>o.getFields(),t=()=>o.getRoles();return{confirm:null,hostId(n,r){return`${o.uid}-rb-host-${gt[r]||"cal"}-${n}`},model(n,r){let a=o.cards[n];return r==="validation"?a.validationRules||{rules:[]}:r==="readonly"?a.readonlyRules||{rules:[]}:r==="hidden"?a.hiddenRules||{rules:[]}:r==="color"?a.colorRules||{rules:[]}:a.calculationRules||{rules:[],else:{kind:"string",value:""}}},ensureModel(n,r){let a=o.cards[n];return r==="validation"?a.validationRules||(a.validationRules={rules:[]}):r==="readonly"?a.readonlyRules||(a.readonlyRules={rules:[]}):r==="hidden"?a.hiddenRules||(a.hiddenRules={rules:[]}):r==="color"?a.colorRules||(a.colorRules={rules:[]}):a.calculationRules||(a.calculationRules={rules:[],else:{kind:"string",value:""}})},newCond(n){let r=o.cards[n]&&o.cards[n].key||e()[0]&&e()[0].key||"";return{field:r,operator:r==="currentUserRole"||r==="currentUser"?"equals":"isEmpty",value:""}},newRule(n,r){let a={combinator:"AND",conditions:[this.newCond(r)]};return n==="validation"?{when:a,message:"Can't be empty"}:n==="calculation"?{when:a,result:{kind:"string",value:""}}:n==="color"?{when:a,color:U[0]}:{when:a}},resolveResult(n,r){let a=this.ensureModel(n,"calculation");return r==="else"?a.else:a.rules[r].result},peekResult(n,r){let a=this.model(n,"calculation");return r==="else"?a.else:a.rules[r]&&a.rules[r].result||{kind:"string",value:""}},addRule(n,r){this.ensureModel(n,r).rules.push(this.newRule(r,n)),this.render(n,r)},removeRule(n,r,a){this.ensureModel(n,r).rules.splice(a,1),this.render(n,r)},requestRemoveRule(n,r,a){this.confirm=`${n}:${r}:${a}`,this.render(n,r,!0)},cancelRemove(n,r){this.render(n,r)},setCombinator(n,r,a,l){this.ensureModel(n,r).rules[a].when.combinator=l,this.render(n,r)},addCond(n,r,a){this.ensureModel(n,r).rules[a].when.conditions.push(this.newCond(n)),this.render(n,r)},removeCond(n,r,a,l){let s=this.ensureModel(n,r).rules[a].when.conditions;s.splice(l,1),s.length||s.push(this.newCond(n)),this.render(n,r)},setField(n,r,a,l,s){let b=this.ensureModel(n,r).rules[a].when.conditions[l];if(b.field=s,W(e(),s).includes(b.operator)||(b.operator=W(e(),s)[0]),s==="currentUser"&&b.valueMode!=="literal"&&(b.valueMode="field",!b.valueField)){let h=e().find(v=>v.key!=="currentUser"&&v.key!=="currentUserRole");b.valueField=h?h.key:""}this.render(n,r)},setOperator(n,r,a,l,s){this.ensureModel(n,r).rules[a].when.conditions[l].operator=s,this.render(n,r)},setValue(n,r,a,l,s){this.ensureModel(n,r).rules[a].when.conditions[l].value=s,this.commit(n,r)},setValueMode(n,r,a,l,s){let b=this.ensureModel(n,r).rules[a].when.conditions[l];if(b.valueMode=s,s==="field"&&!b.valueField){let h=e();b.valueField=h[0]&&h[0].key||""}this.render(n,r)},setValueField(n,r,a,l,s){this.ensureModel(n,r).rules[a].when.conditions[l].valueField=s,this.commit(n,r)},setMessage(n,r,a){this.ensureModel(n,"validation").rules[r].message=ne(a),this.commit(n,"validation")},setRuleColor(n,r,a){this.ensureModel(n,"color").rules[r].color=a,this.render(n,"color")},setCalcTrigger(n,r){o.cards[n].calculationTrigger=r,o.renderGrids(),o.notifyChange()},setResultKind(n,r,a){let l=this.resolveResult(n,r);l.kind=a,a==="field"&&!l.field&&(l.field=e()[0].key),a==="boolean"&&l.value!=="true"&&l.value!=="false"&&(l.value="true"),this.render(n,"calculation")},setResultValue(n,r,a){this.resolveResult(n,r).value=a,this.commit(n,"calculation"),this.refreshJsonError(n,r)},setResultField(n,r,a){this.resolveResult(n,r).field=a,this.commit(n,"calculation")},setDateType(n,r,a){let l=this.resolveResult(n,r);l.dateType=a,a==="relative"&&!l.relativeField&&(l.relativeField=e()[0]&&e()[0].key||"",l.relativeDays=0),this.render(n,"calculation")},setDateRelativeField(n,r,a){this.resolveResult(n,r).relativeField=a,this.commit(n,"calculation")},setDateRelativeDays(n,r,a){this.resolveResult(n,r).relativeDays=a!==""?Number(a):0,this.commit(n,"calculation")},setFormulaDecimals(n,r,a){this.resolveResult(n,r).decimals=a!==""?Number(a):2,this.commit(n,"calculation")},handleFormulaInput(n,r,a){this.resolveResult(n,r).value=a,this.commit(n,"calculation")},insertFormulaText(n,r,a){let l=o.$(`${o.uid}-formula-input-${r}-${n}`);if(!l)return;let s=l.selectionStart??l.value.length,b=l.selectionEnd??l.value.length,h=l.value,v=h.substring(0,s)+a+h.substring(b);l.value=v,l.focus();let g=s+a.length;a.endsWith(")")&&(g=s+a.indexOf("(")+1),l.setSelectionRange(g,g),this.handleFormulaInput(n,r,v)},insertFormulaField(n,r,a){this.insertFormulaText(n,r,`[${a}]`)},refreshJsonError(n,r){let a=o.$(`${o.uid}-rb-jsonerr-${r}-${n}`);if(!a)return;let l=this.peekResult(n,r),s="";try{l.value&&JSON.parse(l.value)}catch(b){s=b.message}a.textContent=s?"Invalid JSON: "+s:""},condHtml(n,r,a,l,s,b){let h=o.uid,v=`<select class="f" onchange="__dbb(${h}).rb.setField(${n},'${r}',${a},${l},this.value)">`+e().map(d=>`<option value="${m(d.key)}" ${d.key===s.field?"selected":""}>${m(d.label)}</option>`).join("")+"</select>",g=`<select class="op" onchange="__dbb(${h}).rb.setOperator(${n},'${r}',${a},${l},this.value)">`+W(e(),s.field).map(d=>`<option value="${d}" ${d===s.operator?"selected":""}>${m(L[d].label)}</option>`).join("")+"</select>",R=b?`<button class="rb-x" title="Remove condition" onclick="__dbb(${h}).rb.removeCond(${n},'${r}',${a},${l})">\u2715</button>`:"";return`<div class="rb-cond"><div class="row1">${v}</div><div class="row2">${g}${this.rhsEditor(n,r,a,l,s)}${R}</div></div>`},rhsEditor(n,r,a,l,s){let b=o.uid,h=L[s.operator];if(!h||!h.needsValue)return"";let v=s.valueMode==="field"?"field":"literal",g=`<span class="rb-rhsmode"><button class="${v==="literal"?"on":""}" title="Compare to a typed value" onclick="__dbb(${b}).rb.setValueMode(${n},'${r}',${a},${l},'literal')">Value</button><button class="${v==="field"?"on":""}" title="Compare to another field" onclick="__dbb(${b}).rb.setValueMode(${n},'${r}',${a},${l},'field')">Field</button></span>`,R;return v==="field"?R=`<select class="val" onchange="__dbb(${b}).rb.setValueField(${n},'${r}',${a},${l},this.value)">`+e().map(d=>`<option value="${m(d.key)}" ${d.key===s.valueField?"selected":""}>${m(d.label)}</option>`).join("")+"</select>":s.field==="currentUserRole"?R=`<select class="val" onchange="__dbb(${b}).rb.setValue(${n},'${r}',${a},${l},this.value)"><option value="">-- select role --</option>`+t().map(d=>`<option value="${m(d)}" ${d===s.value?"selected":""}>${m(d)}</option>`).join("")+"</select>":R=`<input class="val" type="${B.includes(s.operator)||(P(e(),s.field)||{}).type==="number"&&(s.operator==="equals"||s.operator==="notEquals")?"number":"text"}" value="${m(s.value??"")}" placeholder="value" oninput="__dbb(${b}).rb.setValue(${n},'${r}',${a},${l},this.value)">`,g+R},valueEditor(n,r){let a=o.uid,l=this.peekResult(n,r),s=r==="else"?"'else'":r,b=`<select class="k" onchange="__dbb(${a}).rb.setResultKind(${n},${s},this.value)">`+he.map(([v,g])=>`<option value="${v}" ${v===l.kind?"selected":""}>${g}</option>`).join("")+"</select>",h="";if(l.kind==="number")h=`<input type="number" value="${m(l.value??"")}" placeholder="0" oninput="__dbb(${a}).rb.setResultValue(${n},${s},this.value)">`;else if(l.kind==="string")h=`<input type="text" value="${m(l.value??"")}" placeholder="some text" oninput="__dbb(${a}).rb.setResultValue(${n},${s},this.value)">`;else if(l.kind==="boolean")h=`<select onchange="__dbb(${a}).rb.setResultValue(${n},${s},this.value)"><option value="true" ${l.value!=="false"?"selected":""}>true</option><option value="false" ${l.value==="false"?"selected":""}>false</option></select>`;else if(l.kind==="date"){let v=l.dateType||"today",g=`<select onchange="__dbb(${a}).rb.setDateType(${n}, ${s}, this.value)"><option value="today" ${v==="today"?"selected":""}>Today</option><option value="firstOfMonth" ${v==="firstOfMonth"?"selected":""}>First of Month</option><option value="relative" ${v==="relative"?"selected":""}>Relative to Field</option></select>`,R="";if(v==="today")R=`<span style="font-size:11px;color:#64748b;font-style:italic;">Resolves to today's date</span>`;else if(v==="firstOfMonth")R='<span style="font-size:11px;color:#64748b;font-style:italic;">Resolves to 1st of current month</span>';else if(v==="relative"){let d=l.relativeField||e()[0]&&e()[0].key||"",p=l.relativeDays!==void 0?l.relativeDays:0,f=`<select onchange="__dbb(${a}).rb.setDateRelativeField(${n}, ${s}, this.value)">`+e().map(C=>`<option value="${m(C.key)}" ${d===C.key?"selected":""}>${m(C.label)}</option>`).join("")+"</select>",x=`<input type="number" value="${p}" style="width:50px;" oninput="__dbb(${a}).rb.setDateRelativeDays(${n}, ${s}, this.value)">`;R=`<div style="display:flex;gap:4px;align-items:center;flex-wrap:wrap;">${f} ${x} <span style="font-size:11px;color:#64748b;">days</span></div>`}h=`<div style="display:flex;gap:6px;align-items:center;flex-wrap:wrap;">${g} ${R}</div>`}else if(l.kind==="field")h=`<select onchange="__dbb(${a}).rb.setResultField(${n},${s},this.value)">`+e().map(v=>`<option value="${m(v.key)}" ${v.key===l.field?"selected":""}>${m(v.label)}</option>`).join("")+"</select>";else if(l.kind==="object"){let v="";try{l.value&&JSON.parse(l.value)}catch(g){v=g.message}h=`<textarea rows="2" style="font-family:monospace;" placeholder='{ "key": "value" }' oninput="__dbb(${a}).rb.setResultValue(${n},${s},this.value)">${m(l.value??"")}</textarea><div class="rb-jsonerr" id="${a}-rb-jsonerr-${r}-${n}">${v?"Invalid JSON: "+m(v):""}</div>`}else{let v=l.value??"";h=`
555
+ <div class="formula-editor-container">
556
+ <div class="formula-guide">
557
+ <div><strong>Formula Guide:</strong> Reference fields using <code>[Field Name]</code>. Use <code>??</code> for fallbacks (e.g. <code>([A] ?? [B])</code>). Results round to the decimals below.</div>
558
+ </div>
559
+ <div class="formula-input-wrapper">
560
+ <input type="text" id="${a}-formula-input-${r}-${n}" value="${m(v)}" placeholder="e.g., ([Cost A] ?? [Cost B]) * 0.5" oninput="__dbb(${a}).rb.handleFormulaInput(${n}, ${s}, this.value)" class="formula-input-field">
561
+ </div>
562
+ <div class="formula-toolbar" style="justify-content:space-between;">
563
+ <div class="formula-toolbar">
564
+ ${["+","-","*","/","^","(",")"].map(g=>`<button type="button" class="formula-tool-btn" onclick="__dbb(${a}).rb.insertFormulaText(${n}, ${s}, '${g}')">${g}</button>`).join("")}
565
+ <button type="button" class="formula-tool-btn func" onclick="__dbb(${a}).rb.insertFormulaText(${n}, ${s}, ' ?? ')" title="Nullish coalescing (fallback)">??</button>
566
+ </div>
567
+ <div class="formula-decimals-row" style="display:flex;gap:8px;align-items:center;">
568
+ <label style="font-size:11px;font-weight:600;color:#475569;">Round to decimals:</label>
569
+ <input type="number" value="${l.decimals!==void 0?l.decimals:2}" min="0" max="10" style="width:50px;" oninput="__dbb(${a}).rb.setFormulaDecimals(${n}, ${s}, this.value)">
570
+ </div>
571
+ </div>
572
+ <div class="formula-field-pills-label">Click to insert field:</div>
573
+ <div class="formula-field-pills">
574
+ ${e().map(g=>`<button type="button" class="formula-field-pill" onclick="__dbb(${a}).rb.insertFormulaField(${n}, ${s}, '${A(g.label)}')">${m(g.label)}</button>`).join("")}
575
+ </div>
576
+ </div>`}return`<div class="rb-vrow">${b}<div class="vb">${h}</div></div>`},colorPalette(n,r){let a=o.uid,l=this.model(n,"color"),s=l.rules[r]&&l.rules[r].color||"",b=g=>`__dbb(${a}).rb.setRuleColor(${n}, ${r}, '${g}')`,h=U.map(g=>`<button type="button" class="rb-swatch ${s===g?"sel":""}" style="background:${g}" title="${m(g)}" onclick="${b(g)}"></button>`).join(""),v=`<button type="button" class="rb-swatch none ${s?"":"sel"}" title="No color" onclick="${b("")}">${S("close",{size:12})}</button>`;return`<div class="rb-swatches">${h}${v}</div>`},ruleHtml(n,r,a,l){let s=o.uid,b=r==="calculation"?"calc":r==="validation"?"":r,h=a.when.conditions,v="";h.forEach((R,d)=>{d>0&&(v+=`<div class="rb-combo"><button class="${a.when.combinator==="AND"?"on":""}" onclick="__dbb(${s}).rb.setCombinator(${n},'${r}',${l},'AND')">AND</button><button class="${a.when.combinator==="OR"?"on":""}" onclick="__dbb(${s}).rb.setCombinator(${n},'${r}',${l},'OR')">OR</button></div>`),v+=this.condHtml(n,r,l,d,R,h.length>1)});let g;return r==="calculation"?g=`<div class="rb-kw then">RETURN</div>${this.valueEditor(n,l)}`:r==="color"?g=`<div class="rb-kw then">USE COLOR</div>${this.colorPalette(n,l)}`:r==="validation"?g=`<div class="rb-kw then">THEN SHOW</div><input class="rb-msg" type="text" value="${m(a.message||"")}" placeholder="Can't be empty" oninput="__dbb(${s}).rb.setMessage(${n},${l},this.value)">`:r==="readonly"?g='<div class="rb-kw then">\u2192 make this field READ-ONLY</div>':g='<div class="rb-kw then">\u2192 HIDE this field</div>',`<div class="rb-rule">
577
+ <div class="rb-head">
578
+ <span class="rb-idx ${b}">Rule ${l+1}</span>
579
+ <span class="rb-spacer"></span>
580
+ ${this.confirm===`${n}:${r}:${l}`?`<span class="delete-confirm-wrapper"><button class="control-btn confirm-yes-btn" title="Confirm delete" onclick="__dbb(${s}).rb.removeRule(${n},'${r}',${l})">Delete</button><button class="control-btn confirm-no-btn" title="Cancel delete" onclick="__dbb(${s}).rb.cancelRemove(${n},'${r}')">No</button></span>`:`<button class="control-btn delete-btn" title="Delete rule" onclick="__dbb(${s}).rb.requestRemoveRule(${n},'${r}',${l})">${S("delete",{size:16})}</button>`}
581
+ </div>
582
+ <div class="rb-kw">IF</div>
583
+ ${v}
584
+ <button class="rb-add" onclick="__dbb(${s}).rb.addCond(${n},'${r}',${l})">+ condition</button>
585
+ <div style="margin-top:6px;">${g}</div>
586
+ </div>`},buildHtml(n,r,a){let l=o.uid,s=a.rules.map((p,f)=>this.ruleHtml(n,r,p,f)).join(""),b=`<button class="rb-addrule" onclick="__dbb(${l}).rb.addRule(${n},'${r}')">+ Add rule</button>`,h=p=>`<div class="rb-plain" id="${l}-rb-plain-${p}-${n}"></div>`;if(r==="validation")return s+b+h("val");if(r==="readonly")return s+b+h("ro");if(r==="hidden")return s+b+h("hid");if(r==="color")return s+b+h("col");let v=o.cards[n].calculationTrigger==="onUpdate"?"onUpdate":"onInit",g=`<div class="calc-trigger">
587
+ <span class="calc-trigger-label">Compute</span>
588
+ <span class="rb-rhsmode">
589
+ <button class="${v==="onInit"?"on":""}" title="Run once to set the initial/default value (field stays editable)" onclick="__dbb(${l}).rb.setCalcTrigger(${n}, 'onInit')">On init (default)</button>
590
+ <button class="${v==="onUpdate"?"on":""}" title="Recompute on every change (field becomes read-only)" onclick="__dbb(${l}).rb.setCalcTrigger(${n}, 'onUpdate')">On update (read-only)</button>
591
+ </span>
592
+ </div>`,d=`<div class="rb-else"><div class="rb-kw then" style="margin-bottom:4px;">${v==="onUpdate"?"OTHERWISE USE":"DEFAULT VALUE"}</div>${this.valueEditor(n,"else")}</div>`;return g+d+s+b+h("cal")},show(n,r){this.confirm=null;let a=o.$(this.hostId(n,r));a&&(a.innerHTML=this.buildHtml(n,r,this.model(n,r)),this.renderPlain(n,r))},render(n,r,a){a||(this.confirm=null);let l=o.$(this.hostId(n,r));l&&(l.innerHTML=this.buildHtml(n,r,this.model(n,r)),this.commit(n,r))},renderPlain(n,r){let a=o.cards[n],l=mt[r]||"cal",s=o.$(`${o.uid}-rb-plain-${l}-${n}`);if(!s)return;let b=r==="readonly"?a.readonlyRoles:r==="hidden"?a.hiddenRoles:void 0;s.innerHTML='<span class="rb-plain-label">In plain language</span>'+m(me(e(),r,this.model(n,r),b))},isConfigured(n,r){let a=o.cards[n];if(r==="validation")return!!(a.validationRules&&a.validationRules.rules.length>0);if(r==="readonly")return!!(a.readonlyRules&&a.readonlyRules.rules.length>0||a.readonlyRoles&&a.readonlyRoles.length>0);if(r==="hidden")return!!(a.hiddenRules&&a.hiddenRules.rules.length>0||a.hiddenRoles&&a.hiddenRoles.length>0);if(r==="color")return!!(a.colorRules&&a.colorRules.rules.length>0);let l=a.calculationRules;if(!l)return!1;if(l.rules.length>0)return!0;let s=l.else;return!!(s&&!(s.kind==="string"&&(s.value==null||s.value==="")))},commit(n,r){let a=o.cards[n],l=this.isConfigured(n,r);r==="validation"?(a.validationCode=l?M(e(),this.model(n,r)):"",o.updateButtonVisuals(n,"validationCode",l)):r==="readonly"?(a.readonlyCode=l?I(e(),a.readonlyRules,"false",a.readonlyRoles):"",o.updateButtonVisuals(n,"readonlyCode",l)):r==="hidden"?(a.hiddenCode=l?I(e(),a.hiddenRules,"false",a.hiddenRoles):"",o.updateButtonVisuals(n,"hiddenCode",l)):r==="color"?(a.colorCode=l?q(e(),this.model(n,r)):"",o.updateButtonVisuals(n,"colorCode",l)):(a.calculation=l?z(e(),this.model(n,r)):"",o.updateButtonVisuals(n,"calculation",l)),this.renderPlain(n,r),o.notifyChange()}}}function ye(o){return{ensure(e){return(!e.table||typeof e.table!="object")&&(e.table={width:e.width,displayedByDefault:!0,hidden:!1}),typeof e.table.width!="number"&&(e.table.width=e.width),typeof e.table.displayedByDefault!="boolean"&&(e.table.displayedByDefault=!0),typeof e.table.hidden!="boolean"&&(e.table.hidden=!1),e.table},buildConfig(){let e=[];return o.rowIds.forEach(t=>{o.cards.filter(i=>i.row===t).forEach(i=>{let n=this.ensure(i);e.push({key:i.key,label:i.label,type:i.type,width:n.width,displayedByDefault:n.displayedByDefault,hidden:n.hidden})})}),{columns:e}},render(){let e=o.$(`${o.uid}-panel-table`);if(!e)return;let t=o.uid;if(!o.cards.length){e.innerHTML='<div class="view-empty">No fields yet. Add fields on the Dialog tab.</div>';return}let i=[];o.rowIds.forEach(r=>{o.cards.filter(a=>a.row===r).forEach(a=>{let l=o.cards.indexOf(a),s=this.ensure(a),b=(o.registry.get(a.type)||{}).label||a.type;i.push(`<tr>
593
+ <td>${m(a.label||"")}</td>
594
+ <td><code>${m(a.key||"")}</code></td>
595
+ <td>${m(b)}</td>
596
+ <td><input class="table-w" type="number" min="1" value="${m(String(s.width))}" oninput="__dbb(${t}).tableView.setWidth(${l}, this.value)"></td>
597
+ <td class="table-check"><input type="checkbox" ${s.displayedByDefault?"checked":""} onchange="__dbb(${t}).tableView.setDisplayed(${l}, this.checked)"></td>
598
+ <td class="table-check"><input type="checkbox" ${s.hidden?"checked":""} onchange="__dbb(${t}).tableView.setHidden(${l}, this.checked)"></td>
599
+ </tr>`)})});let n=o._devModeOn()?`<div class="view-json-title">Table JSON</div><pre class="debug-panel" id="${t}-table-json"></pre>`:"";e.innerHTML=`<table class="view-table">
600
+ <thead><tr><th>Label</th><th>Key</th><th>Type</th><th>Width</th><th>Displayed on default</th><th>Hidden</th></tr></thead>
601
+ <tbody>${i.join("")}</tbody>
602
+ </table>
603
+ ${n}`,this._renderJson()},_renderJson(){let e=o.$(`${o.uid}-table-json`);e&&(e.textContent=JSON.stringify(this.buildConfig(),null,2))},setWidth(e,t){let i=o.cards[e];if(!i)return;let n=parseInt(t,10);this.ensure(i).width=Number.isFinite(n)?n:0,this._commit()},setDisplayed(e,t){let i=o.cards[e];i&&(this.ensure(i).displayedByDefault=!!t,this._commit())},setHidden(e,t){let i=o.cards[e];i&&(this.ensure(i).hidden=!!t,this._commit())},_commit(){this._renderJson(),o.updateOutput(),o.dispatchEvent(new CustomEvent("change",{detail:o.getConfig(),bubbles:!0,composed:!0}))}}}var Z=["#3f51b5","#fea20f","#0fa216","#f44336","#9c27b0","#00bcd4","#e91e63","#795548","#607d8b"],Ue=[["bar","Bar"],["line","Line"],["pie","Pie"],["doughnut","Doughnut"]],Ze=[["count","Count of rows"],["sum","Sum of a number field"],["avg","Average of a number field"]];function we(o){return o&&(o.type==="number"||o.valueBucket==="number")}function F(o,e){return(o||[]).find(t=>t.key===e)}function Je(o,e){let t=F(o,e);return t?t.label||t.key:e||"\u2014"}function re(o){return!o||!Array.isArray(o.options)||!o.options.length?null:o.options.map(e=>String(e&&typeof e=="object"?e.label!=null?e.label:e.value!=null?e.value:"":e))}function ae(o){return o===""||o==null?"(empty)":o===!0?"Yes":o===!1?"No":String(o)}function $e(o){let e=(o||[]).find(i=>re(i)),t=(o||[]).find(we);return{type:"bar",dimension:(e||(o||[])[0]||{}).key||"",series:"",measure:"count",measureField:(t||{}).key||""}}function j(o,e){let t=Object.assign($e(e),o||{});if(F(e,t.dimension)||(t.dimension=$e(e).dimension),t.series&&!F(e,t.series)&&(t.series=""),["bar","line","pie","doughnut"].includes(t.type)||(t.type="bar"),["count","sum","avg"].includes(t.measure)||(t.measure="count"),t.measure!=="count"){let i=F(e,t.measureField);if(!we(i)){let n=(e||[]).find(we);t.measureField=n?n.key:""}}return t}function Ce(o,e){return o.measure==="count"?"Count":`${o.measure==="sum"?"Sum":"Avg"} of ${Je(e,o.measureField)}`}function He(o,e,t){let i=re(o);if(i&&i.length)return i.map(ae);let n=new Set;return(e||[]).forEach(r=>{let a=r[t];(Array.isArray(a)?a.length?a:[""]:[a]).forEach(l=>n.add(ae(l)))}),[...n]}function xe(o,e,t){let i=o[e];return(Array.isArray(i)?i.map(ae):[ae(i)]).includes(t)}function Pe(o,e){if(o.measure==="count")return e.length;let t=e.map(n=>Number(n[o.measureField])).filter(n=>Number.isFinite(n));if(!t.length)return 0;let i=t.reduce((n,r)=>n+r,0);return o.measure==="sum"?i:Math.round(i/t.length*100)/100}function G(o,e,t){let i=j(o,e);t=t||[];let n=He(F(e,i.dimension),t,i.dimension),r=Ce(i,e),a;if(i.series)a=He(F(e,i.series),t,i.series).map((b,h)=>({label:b,data:n.map(v=>Pe(i,t.filter(g=>xe(g,i.dimension,v)&&xe(g,i.series,b)))),backgroundColor:Z[h%Z.length]}));else{let s=["pie","doughnut","bar"].includes(i.type);a=[{label:r,data:n.map(b=>Pe(i,t.filter(h=>xe(h,i.dimension,b)))),backgroundColor:s?n.map((b,h)=>Z[h%Z.length]):Z[0],borderColor:Z[0],fill:!1,tension:.3}]}let l=!!i.series||["pie","doughnut"].includes(i.type);return{type:i.type,data:{labels:n,datasets:a},options:{responsive:!0,maintainAspectRatio:!1,animation:!1,plugins:{legend:{display:l},title:{display:!0,text:`${r} by ${Je(e,i.dimension)}`}}}}}function Be(o,e){let t=j(o,e),i=(re(F(e,t.dimension))||["Group A","Group B","Group C"]).map(String),n=t.series?(re(F(e,t.series))||["Series 1","Series 2"]).map(String):[null],r=[];return i.forEach((a,l)=>n.forEach((s,b)=>{let h=(l*7+b*13+5)%6+2;for(let v=0;v<h;v++){let g={[t.dimension]:a};t.series&&(g[t.series]=s),t.measureField&&(g[t.measureField]=1+(l+b+v)%9),r.push(g)}})),r}var vt="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js";function _e(o){let e=null,t=null,i=null,n=()=>o.cards,r=()=>o.cards.filter(s=>s.type==="number"),a=()=>(e=j(e||{},n()),e);return{getSettings(){return j(e||{},n())},getSettingsString(){return JSON.stringify(this.getSettings())},setSettings(s){e=j(typeof s=="string"?JSON.parse(s||"{}"):s||{},n())},buildChartJsConfig(){let s=a();return G(s,n(),Be(s,n()))},setType(s){a().type=s,o.notifyChange()},setDimension(s){a().dimension=s,o.notifyChange()},setSeries(s){a().series=s,o.notifyChange()},setMeasure(s){a().measure=s,o.notifyChange()},setMeasureField(s){a().measureField=s,o.notifyChange()},render(){let s=o.$(`${o.uid}-panel-chart`);if(!s)return;let b=o.uid;if(!o.cards.length){s.innerHTML='<div class="view-empty">No fields yet. Add fields on the Dialog tab.</div>';return}let h=a(),v=(d,p)=>(p?`<option value="" ${d===""?"selected":""}>\u2014 none \u2014</option>`:"")+o.cards.map(f=>`<option value="${m(f.key)}" ${f.key===d?"selected":""}>${m(f.label||f.key)}</option>`).join(""),g=d=>r().map(p=>`<option value="${m(p.key)}" ${p.key===d?"selected":""}>${m(p.label||p.key)}</option>`).join(""),R=h.measure==="count"?"":`
604
+ <div class="chart-field">
605
+ <label>Number field</label>
606
+ <select onchange="__dbb(${b}).chartView.setMeasureField(this.value)">${g(h.measureField)||'<option value="">(no number fields)</option>'}</select>
607
+ <span class="chart-hint">Which numeric column to ${h.measure==="sum"?"add up":"average"}.</span>
608
+ </div>`;s.innerHTML=`
609
+ <div class="chart-config">
610
+ <p class="chart-intro">Build a chart from the data collected by this form. Choose what to <b>group by</b> and what to <b>measure</b>.</p>
611
+ <div class="chart-fields">
612
+ <div class="chart-field">
613
+ <label>1 \xB7 Group by (X-axis)</label>
614
+ <select onchange="__dbb(${b}).chartView.setDimension(this.value)">${v(h.dimension,!1)}</select>
615
+ <span class="chart-hint">Each value of this field becomes a bar / slice.</span>
616
+ </div>
617
+ <div class="chart-field">
618
+ <label>2 \xB7 Measure (Y-axis)</label>
619
+ <select onchange="__dbb(${b}).chartView.setMeasure(this.value)">${Ze.map(([d,p])=>`<option value="${d}" ${d===h.measure?"selected":""}>${p}</option>`).join("")}</select>
620
+ <span class="chart-hint">What the bar height represents.</span>
621
+ </div>
622
+ ${R}
623
+ <div class="chart-field">
624
+ <label>3 \xB7 Split into series (optional)</label>
625
+ <select onchange="__dbb(${b}).chartView.setSeries(this.value)">${v(h.series,!0)}</select>
626
+ <span class="chart-hint">Adds a coloured dataset per value.</span>
627
+ </div>
628
+ <div class="chart-field">
629
+ <label>Chart type</label>
630
+ <select onchange="__dbb(${b}).chartView.setType(this.value)">${Ue.map(([d,p])=>`<option value="${d}" ${d===h.type?"selected":""}>${p}</option>`).join("")}</select>
631
+ </div>
632
+ </div>
633
+ <div class="chart-summary">${m(Ce(h,o.cards))} by ${m((o.cards.find(d=>d.key===h.dimension)||{}).label||h.dimension||"\u2014")}${h.series?`, split by ${m((o.cards.find(d=>d.key===h.series)||{}).label||h.series)}`:""}.</div>
634
+ </div>
635
+ <div class="chart-preview"><canvas id="${b}-chart-canvas"></canvas></div>
636
+ <div class="chart-note" id="${b}-chart-note">Preview uses sample data. The same configuration runs over real data on the runner page.</div>
637
+ ${o._devModeOn()?`<div class="view-json-title">Chart Settings</div><pre class="debug-panel" id="${b}-chart-json"></pre>`:""}`,this._renderJson(),this._drawPreview()},_renderJson(){let s=o.$(`${o.uid}-chart-json`);s&&(s.textContent=JSON.stringify(this.getSettings(),null,2))},_ensureChartJs(){return typeof window<"u"&&window.Chart?Promise.resolve(window.Chart):i||(i=new Promise((s,b)=>{let h=document.createElement("script");h.src=vt,h.onload=()=>s(window.Chart),h.onerror=()=>b(new Error("Chart.js failed to load")),document.head.appendChild(h)}),i)},_drawPreview(){let s=o.$(`${o.uid}-chart-canvas`);s&&this._ensureChartJs().then(b=>{s.isConnected&&(t&&(t.destroy(),t=null),t=new b(s.getContext("2d"),this.buildChartJsConfig()))}).catch(()=>{let b=o.$(`${o.uid}-chart-note`);b&&(b.textContent="Chart.js preview unavailable (offline). The configuration is still saved with the config.")})}}}var yt=190,We="http://www.w3.org/2000/svg";function ke(o){let e=null,t=1,i=null,n=0,r=0,a=1,l=(d,p,f)=>Math.max(p,Math.min(f,d));function s(){return(!e||typeof e!="object")&&(e={states:[],transitions:[]}),Array.isArray(e.states)||(e.states=[]),Array.isArray(e.transitions)||(e.transitions=[]),e.states.forEach((d,p)=>{typeof d.x!="number"&&(d.x=40+p%4*220),typeof d.y!="number"&&(d.y=40+Math.floor(p/4)*150)}),e}let b=()=>`s${t++}`,h=d=>s().states.find(p=>p.id===d),v=()=>o.$(`${o.uid}-wf-canvas`),g=()=>o.$(`${o.uid}-wf-content`);return{getConfig(){return JSON.parse(JSON.stringify(s()))},setConfig(d){e=d&&typeof d=="object"?JSON.parse(JSON.stringify(d)):{states:[],transitions:[]},i=null,n=0,r=0,a=1,s();let p=0;e.states.forEach(f=>{let x=/^s(\d+)$/.exec(f.id||"");x&&(p=Math.max(p,Number(x[1])))}),t=p+1},addState(){let d=s(),p=d.states.length,f=b();d.states.push({id:f,name:`State ${p+1}`,role:"",x:40+p%4*220-n,y:40+Math.floor(p/4)*150-r}),i=f,o.notifyChange()},removeState(d){let p=s();p.states=p.states.filter(f=>f.id!==d),p.transitions=p.transitions.filter(f=>f.from!==d&&f.to!==d),i===d&&(i=null),o.notifyChange()},setStateRole(d,p){let f=h(d);f&&(f.role=p),o.notifyChange()},setStateColor(d,p){let f=h(d);f&&(f.color=p||""),o.notifyChange()},setStateName(d,p){let f=h(d);if(!f)return;f.name=p;let x=o.shadowRoot&&o.shadowRoot.activeElement,C=v(),c=C&&C.querySelector(`.wf-node[data-id="${CSS.escape(d)}"] .wf-node-title`);c&&c!==x&&c.value!==p&&(c.value=p);let u=o.$(`${o.uid}-wf-insp-name`);u&&u!==x&&u.value!==p&&(u.value=p),this._commitQuiet()},handleNameKeydown(d,p){d.key==="Enter"&&(d.target.blur(),o.notifyChange())},setStateNumber(d,p){let f=s(),x=f.states.findIndex(u=>u.id===d);if(x===-1)return;let C=parseInt(p,10)-1;if(isNaN(C)||(C=Math.max(0,Math.min(f.states.length-1,C)),x===C))return;let[c]=f.states.splice(x,1);f.states.splice(C,0,c),o.notifyChange()},addTransitionFrom(d){let p=s(),f=p.states.find(x=>x.id!==d)||p.states.find(x=>x.id===d);f&&(p.transitions.push({from:d,to:f.id,role:""}),o.notifyChange())},addTransitionBetween(d,p){let f=s();d===p||!h(d)||!h(p)||(f.transitions.some(x=>x.from===d&&x.to===p)||f.transitions.push({from:d,to:p,role:""}),i=d,o.notifyChange())},addConnectedState(d,p,f){let x=s();if(!h(d))return;let C=b();x.states.push({id:C,name:`State ${x.states.length+1}`,role:"",x:Math.round(p),y:Math.round(f)}),x.transitions.push({from:d,to:C,role:""}),i=C,o.notifyChange()},removeTransition(d){s().transitions.splice(d,1),o.notifyChange()},setTransition(d,p,f){let x=s().transitions[d];x&&(x[p]=f),o.notifyChange()},select(d,p=!1){if(i!==d&&(i=d,this.render(),p)){let f=v(),x=f&&f.querySelector(`.wf-node[data-id="${CSS.escape(d)}"] .wf-node-title`);if(x){x.focus();let C=x.value;x.value="",x.value=C}}},_applyTransform(){let d=g();d&&(d.style.transform=`translate(${n}px,${r}px) scale(${a})`)},_zoomAround(d,p,f){let x=a,C=l(x*d,.2,2.5);if(C===x)return;let c=(p-n)/x,u=(f-r)/x;a=C,n=p-c*C,r=f-u*C,this._applyTransform()},zoomIn(){let d=v();this._zoomAround(1.2,d?d.clientWidth/2:0,d?d.clientHeight/2:0)},zoomOut(){let d=v();this._zoomAround(1/1.2,d?d.clientWidth/2:0,d?d.clientHeight/2:0)},fit(){let d=v(),p=g();if(!d||!p)return;let f=[...p.querySelectorAll(".wf-node")];if(!f.length){n=0,r=0,a=1,this._applyTransform();return}let x=1/0,C=1/0,c=-1/0,u=-1/0;f.forEach(E=>{x=Math.min(x,E.offsetLeft),C=Math.min(C,E.offsetTop),c=Math.max(c,E.offsetLeft+E.offsetWidth),u=Math.max(u,E.offsetTop+E.offsetHeight)});let y=40,$=Math.max(1,c-x),k=Math.max(1,u-C),_=d.clientWidth,T=d.clientHeight;a=l(Math.min((_-2*y)/$,(T-2*y)/k),.2,1.5),n=(_-$*a)/2-x*a,r=(T-k*a)/2-C*a,this._applyTransform()},_commitQuiet(){this._renderJson(),o.updateOutput(),o.dispatchEvent(new CustomEvent("change",{detail:o.getConfig(),bubbles:!0,composed:!0}))},render(){let d=o.$(`${o.uid}-panel-workflow`);if(!d)return;let p=o.uid,f=s();i&&!h(i)&&(i=null);let x=f.states.map((c,u)=>`
638
+ <div class="wf-node ${c.id===i?"selected":""}" data-id="${m(c.id)}" style="left:${c.x}px;top:${c.y}px;width:${yt}px;">
639
+ <div class="wf-node-head"${c.color?` style="background:${m(c.color)}22;"`:""}>
640
+ <input type="number" class="wf-node-badge-input" data-id="${m(c.id)}" value="${u+1}" min="1" max="${f.states.length}"
641
+ style="${c.color?`background:${m(c.color)};`:""}"
642
+ onmousedown="event.stopPropagation()"
643
+ onchange="__dbb(${p}).workflowView.setStateNumber('${A(c.id)}', this.value)">
644
+ <input class="wf-node-title" data-id="${m(c.id)}" value="${m(c.name||"")}" placeholder="(unnamed)"
645
+ onfocus="__dbb(${p}).workflowView.select('${A(c.id)}', true)"
646
+ oninput="__dbb(${p}).workflowView.setStateName('${A(c.id)}', this.value)"
647
+ onkeydown="__dbb(${p}).workflowView.handleNameKeydown(event, '${A(c.id)}')"
648
+ >
649
+ </div>
650
+ <div class="wf-node-body">${c.role?`\u{1F512} ${m(c.role)}`:"anyone"}</div>
651
+ <div class="wf-port wf-port-in" title="Incoming transitions"></div>
652
+ <div class="wf-port wf-port-out" data-id="${m(c.id)}" title="Drag to another state to connect"></div>
653
+ </div>`).join(""),C=f.states.length?"":'<div class="wf-canvas-empty">Click <b>+ Add state</b> to create your first workflow step.</div>';d.innerHTML=`
654
+ <div class="wf-toolbar">
655
+ <button class="wf-add" onclick="__dbb(${p}).workflowView.addState()">+ Add state</button>
656
+ <span class="wf-zoom">
657
+ <button title="Zoom out" onclick="__dbb(${p}).workflowView.zoomOut()">\u2212</button>
658
+ <button title="Zoom in" onclick="__dbb(${p}).workflowView.zoomIn()">+</button>
659
+ <button title="Fit whole graph" onclick="__dbb(${p}).workflowView.fit()">\u2922 Fit</button>
660
+ </span>
661
+ </div>
662
+ <div class="wf-canvas" id="${p}-wf-canvas">
663
+ <div class="wf-content" id="${p}-wf-content" style="transform:translate(${n}px,${r}px) scale(${a});">
664
+ <svg class="wf-edges" id="${p}-wf-edges"></svg>
665
+ ${x}
666
+ </div>
667
+ ${C}
668
+ </div>
669
+ ${this._inspectorHtml(f)}
670
+ ${o._devModeOn()?`<div class="view-json-title">Workflow JSON</div><pre class="debug-panel" id="${p}-workflow-json"></pre>`:""}`,this._renderJson(),this._bind(),this._drawEdges()},_colorPalette(d){let p=o.uid,f=d.color||"",x=u=>`__dbb(${p}).workflowView.setStateColor('${A(d.id)}', '${u}')`,C=U.map(u=>`<button type="button" class="rb-swatch ${f===u?"sel":""}" style="background:${u}" title="${m(u)}" onclick="${x(u)}"></button>`).join(""),c=`<button type="button" class="rb-swatch none ${f?"":"sel"}" title="No color" onclick="${x("")}">${S("close",{size:12})}</button>`;return`<div class="rb-swatches">${C}${c}</div>`},_inspectorHtml(d){let p=h(i);if(!p)return"";let f=o.uid,x=d.states.indexOf(p),C=y=>`<option value="" ${y?"":"selected"}>\u2014 anyone \u2014</option>`+o.globalRoles.map($=>`<option value="${m($)}" ${$===y?"selected":""}>${m($)}</option>`).join(""),c=y=>d.states.map($=>`<option value="${m($.id)}" ${$.id===y?"selected":""}>${m($.name||$.id)}</option>`).join(""),u=d.transitions.map((y,$)=>({t:y,i:$})).filter(({t:y})=>y.from===p.id).map(({t:y,i:$})=>`
671
+ <div class="wf-insp-trans">
672
+ <span class="wf-arrow">\u2192</span>
673
+ <select onchange="__dbb(${f}).workflowView.setTransition(${$}, 'to', this.value)">${c(y.to)}</select>
674
+ <span class="wf-lbl">by</span>
675
+ <select onchange="__dbb(${f}).workflowView.setTransition(${$}, 'role', this.value)">${C(y.role)}</select>
676
+ <button class="wf-del" title="Remove" onclick="__dbb(${f}).workflowView.removeTransition(${$})">${S("close",{size:14})}</button>
677
+ </div>`).join("")||'<div class="wf-empty">No outgoing transitions yet.</div>';return`
678
+ <div class="wf-inspector">
679
+ <div class="wf-insp-head">
680
+ <span class="wf-node-badge"${p.color?` style="background:${m(p.color)};"`:""}>${x+1}</span>
681
+ <b>State details</b>
682
+ <span style="flex:1"></span>
683
+ <button class="wf-del" title="Delete state" onclick="__dbb(${f}).workflowView.removeState('${A(p.id)}')">${S("delete",{size:16})}</button>
684
+ <button class="wf-del" title="Close" onclick="__dbb(${f}).workflowView.select(null)">${S("close",{size:16})}</button>
685
+ </div>
686
+ <label class="wf-insp-field"><span>Number</span>
687
+ <input type="number" value="${x+1}" min="1" max="${d.states.length}" style="width: 80px;"
688
+ onchange="__dbb(${f}).workflowView.setStateNumber('${A(p.id)}', this.value)"></label>
689
+ <label class="wf-insp-field"><span>Name</span>
690
+ <input type="text" id="${f}-wf-insp-name" value="${m(p.name||"")}"
691
+ oninput="__dbb(${f}).workflowView.setStateName('${A(p.id)}', this.value)"
692
+ onkeydown="__dbb(${f}).workflowView.handleNameKeydown(event, '${A(p.id)}')"
693
+ ></label>
694
+ <label class="wf-insp-field"><span>Handled by</span>
695
+ <select onchange="__dbb(${f}).workflowView.setStateRole('${A(p.id)}', this.value)">${C(p.role)}</select></label>
696
+ <div class="wf-insp-field"><span>Color</span>${this._colorPalette(p)}</div>
697
+ <div class="wf-insp-sub">Transitions out</div>
698
+ ${u}
699
+ <button class="wf-add wf-add-sm" ${d.states.length<1?"disabled":""} onclick="__dbb(${f}).workflowView.addTransitionFrom('${A(p.id)}')">+ Add transition</button>
700
+ </div>`},_renderJson(){let d=o.$(`${o.uid}-workflow-json`);d&&(d.textContent=JSON.stringify(this.getConfig(),null,2))},_anchor(d,p){let f=g()&&g().querySelector(`.wf-node[data-id="${CSS.escape(d)}"]`);if(!f)return{x:0,y:0};let x=f.offsetLeft,C=f.offsetTop,c=f.offsetWidth,u=f.offsetHeight;return p==="out"?{x:x+c,y:C+u/2}:{x,y:C+u/2}},_path(d,p,f,x){let C=Math.round((d+f)/2);return`M ${d} ${p} H ${C} V ${x} H ${f}`},_drawEdges(){let d=o.$(`${o.uid}-wf-edges`);d&&([...d.querySelectorAll(".wf-edge")].forEach(p=>p.remove()),s().transitions.forEach(p=>{let f=this._anchor(p.from,"out"),x=this._anchor(p.to,"in"),C=document.createElementNS(We,"path");C.setAttribute("class","wf-edge"),C.setAttribute("d",this._path(f.x,f.y,x.x,x.y));let c=h(p.from);c&&c.color&&(C.style.stroke=c.color),d.appendChild(C)}))},_startConnect(d){let p=v(),f=o.$(`${o.uid}-wf-edges`);if(!p||!f)return;let x=this,C=this._anchor(d,"out"),c=document.createElementNS(We,"path");c.setAttribute("class","wf-edge wf-temp-edge"),f.appendChild(c);let u=null,y=()=>p.querySelectorAll(".wf-node.wf-connect-target").forEach(_=>_.classList.remove("wf-connect-target")),$=_=>{let T=p.getBoundingClientRect(),E=(_.clientX-T.left-n)/a,O=(_.clientY-T.top-r)/a;c.setAttribute("d",x._path(C.x,C.y,E,O)),y();let N=o.shadowRoot.elementFromPoint(_.clientX,_.clientY),H=N&&N.closest&&N.closest(".wf-node");u=H?H.getAttribute("data-id"):null,u&&u!==d?H.classList.add("wf-connect-target"):u=null},k=_=>{if(document.removeEventListener("mousemove",$),document.removeEventListener("mouseup",k),y(),c.remove(),u){x.addTransitionBetween(d,u);return}let T=p.getBoundingClientRect();if(_.clientX<T.left||_.clientX>T.right||_.clientY<T.top||_.clientY>T.bottom)return;let E=o.shadowRoot.elementFromPoint(_.clientX,_.clientY);if(E&&E.closest&&E.closest(".wf-node"))return;let O=(_.clientX-T.left-n)/a,N=(_.clientY-T.top-r)/a;Math.hypot(O-C.x,N-C.y)<15||x.addConnectedState(d,O,N-30)};document.addEventListener("mousemove",$),document.addEventListener("mouseup",k)},_bind(){let d=v();if(!d)return;let p=this;d.addEventListener("wheel",f=>{f.preventDefault();let x=d.getBoundingClientRect(),C=f.clientX-x.left,c=f.clientY-x.top,u=f.deltaY<0?1.1:1/1.1;p._zoomAround(u,C,c)},{passive:!1}),d.querySelectorAll(".wf-node").forEach(f=>{let x=f.getAttribute("data-id"),C=f.querySelector(".wf-node-title");C&&C.addEventListener("mousedown",u=>u.stopPropagation());let c=f.querySelector(".wf-port-out");c&&c.addEventListener("mousedown",u=>{u.button===0&&(u.preventDefault(),u.stopPropagation(),p._startConnect(x))}),f.addEventListener("mousedown",u=>{if(u.button!==0)return;u.preventDefault(),u.stopPropagation();let y=h(x),$=u.clientX,k=u.clientY,_=y.x,T=y.y,E=!1,O=H=>{let Ie=H.clientX-$,Fe=H.clientY-k;(Math.abs(Ie)>3||Math.abs(Fe)>3)&&(E=!0),y.x=_+Ie/a,y.y=T+Fe/a,f.style.left=`${y.x}px`,f.style.top=`${y.y}px`,p._drawEdges()},N=()=>{document.removeEventListener("mousemove",O),document.removeEventListener("mouseup",N),E?o.notifyChange():p.select(x)};document.addEventListener("mousemove",O),document.addEventListener("mouseup",N)})}),d.addEventListener("mousedown",f=>{if(f.button!==0||f.target.closest&&f.target.closest(".wf-node"))return;let x=f.clientX,C=f.clientY,c=n,u=r,y=g(),$=!1,k=T=>{let E=T.clientX-x,O=T.clientY-C;(Math.abs(E)>3||Math.abs(O)>3)&&($=!0),n=c+E,r=u+O,p._applyTransform()},_=()=>{document.removeEventListener("mousemove",k),document.removeEventListener("mouseup",_),$||p.select(null)};document.addEventListener("mousemove",k),document.addEventListener("mouseup",_)})}}}var xt="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js",wt=["label","description","empty"],se={ROUND:(o,e=2)=>{let t=Math.pow(10,e);return Math.round(Number(o||0)*t)/t},IF:(o,e,t)=>o?e:t,AND:(...o)=>o.flat(1/0).every(Boolean),OR:(...o)=>o.flat(1/0).some(Boolean),NOT:o=>!o,SUM:(...o)=>o.flat(1/0).reduce((e,t)=>e+(Number(t)||0),0),MIN:(...o)=>Math.min(...o.flat(1/0).map(Number)),MAX:(...o)=>Math.max(...o.flat(1/0).map(Number)),AVERAGE:(...o)=>{let e=o.flat(1/0).map(Number).filter(Number.isFinite);return e.length?e.reduce((t,i)=>t+i,0)/e.length:0}};se.AVG=se.AVERAGE;var Ge=Object.keys(se);function Y(o){if(!o)return null;try{return new Function(...Ge,`return (${o});`)(...Ge.map(t=>se[t]))}catch(e){return console.warn("[dialog-builder preview] could not compile rule:",e,o),null}}function V(o,e,t){if(!o)return t;try{return o(e)}catch{return t}}function Ye(o){return String(o).padStart(2,"0")}function $t(o){return o instanceof Date&&!isNaN(o)?`${o.getFullYear()}-${Ye(o.getMonth()+1)}-${Ye(o.getDate())}`:o==null?"":String(o)}function Re(o){let e=[],t=null,i=null,n="",r={},a=!1,l=!1,s=()=>o.cards.filter(c=>!wt.includes(c.type));function b(c){return(c.options||[]).map(u=>u&&typeof u=="object"?{value:String(u.value!=null?u.value:u.label!=null?u.label:""),label:String(u.label!=null?u.label:u.value)}:{value:String(u),label:String(u)})}function h(c){return Array.isArray(c)?m(c.join(", ")):c===!0?"\u2713":c===!1?"\u2717":m(c??"")}function v(c){if(!c)return!1;if(c.rules&&c.rules.length)return!0;let u=c.else;return!!(u&&!(u.kind==="string"&&(u.value==null||u.value==="")))}function g(){let c=o.getFields();r={},o.cards.forEach(u=>{let y=u.readonlyRules&&u.readonlyRules.rules.length||u.readonlyRoles&&u.readonlyRoles.length,$=u.hiddenRules&&u.hiddenRules.rules.length||u.hiddenRoles&&u.hiddenRoles.length,k=u.validationRules&&u.validationRules.rules.length,_=u.colorRules&&u.colorRules.rules.length,T=v(u.calculationRules);r[u.key]={readonly:y?Y(I(c,u.readonlyRules||{rules:[]},"false",u.readonlyRoles)):null,hidden:$?Y(I(c,u.hiddenRules||{rules:[]},"false",u.hiddenRoles)):null,validation:k?Y(M(c,u.validationRules)):null,color:_?Y(q(c,u.colorRules)):null,calc:T?Y(z(c,u.calculationRules)):null,calcTrigger:u.calculationTrigger==="onUpdate"?"onUpdate":"onInit"}})}function R(c,u){let y=b(c),$=["textarea","comments","richText","dropdownList","radioCards","radioCardsMulti"].includes(c.type)?" full":"",k=m(c.key),_;switch(c.type){case"number":_=`<input type="number" name="${k}" ${u}>`;break;case"checkbox":case"toggle":_=`<input type="checkbox" name="${k}" ${u}>`;break;case"date":_=`<input type="date" name="${k}" ${u}>`;break;case"textarea":case"comments":case"richText":_=`<textarea name="${k}" rows="3" ${u}></textarea>`;break;case"dropdown":_=`<select name="${k}" ${u}><option value="">\u2014</option>${y.map(T=>`<option value="${m(T.value)}">${m(T.label)}</option>`).join("")}</select>`;break;case"dropdownList":_=`<select name="${k}" multiple size="${Math.min(5,Math.max(2,y.length))}" ${u}>${y.map(T=>`<option value="${m(T.value)}">${m(T.label)}</option>`).join("")}</select>`;break;case"radioCards":_=`<div class="pv-opts">${y.map(T=>`<label><input type="radio" name="${k}" value="${m(T.value)}" ${u}>${m(T.label)}</label>`).join("")}</div>`;break;case"radioCardsMulti":_=`<div class="pv-opts">${y.map(T=>`<label><input type="checkbox" name="${k}" value="${m(T.value)}" ${u}>${m(T.label)}</label>`).join("")}</div>`;break;default:_=`<input type="text" name="${k}" ${u}>`}return`<div class="pv-field${$}" data-pv-key="${k}"><span class="pv-label">${m(c.label||c.key)}</span>${_}<span class="pv-error" data-pv-err="${k}"></span></div>`}function d(c){let u={};return s().forEach(y=>{let $=CSS.escape(y.key);if(y.type==="checkbox"||y.type==="toggle"){let _=c.querySelector(`[name="${$}"]`);u[y.key]=!!(_&&_.checked);return}if(y.type==="dropdownList"){let _=c.querySelector(`select[name="${$}"]`);u[y.key]=_?[..._.selectedOptions].map(T=>T.value):[];return}if(y.type==="radioCardsMulti"){u[y.key]=[...c.querySelectorAll(`input[name="${$}"]:checked`)].map(_=>_.value);return}if(y.type==="radioCards"){let _=c.querySelector(`input[name="${$}"]:checked`);u[y.key]=_?_.value:"";return}let k=c.querySelector(`[name="${$}"]`);if(!k){u[y.key]="";return}u[y.key]=y.type==="number"?k.value===""?null:Number(k.value):k.value}),u}function p(c){let u=d(c);return u.currentUserRole=n,u.currentUser="",u}function f(c,u,y){let $=CSS.escape(u.key);if(u.type==="checkbox"||u.type==="toggle"){let T=c.querySelector(`[name="${$}"]`);if(!T)return!1;let E=!!y;return T.checked!==E?(T.checked=E,!0):!1}let k=c.querySelector(`[name="${$}"]`);if(!k||k.multiple)return!1;let _=u.type==="date"?$t(y):y==null?"":String(y);return k.value!==_?(k.value=_,!0):!1}function x(c,u,y){c.querySelectorAll(`[name="${CSS.escape(u.key)}"]`).forEach($=>{$.disabled=!!y})}return{getData(){return JSON.parse(JSON.stringify(e))},setData(c){e=Array.isArray(c)?JSON.parse(JSON.stringify(c)):[]},setPreviewRole(c){n=c||"",this.recompute()},recompute(){let c=o.$(`${o.uid}-pv-form`);c&&this._applyRules(c)},addRow(){let c=o.$(`${o.uid}-pv-form`);if(!c)return;l=!0,this._applyRules(c);let u=p(c),y=[];s().forEach(k=>{let _=r[k.key];if(_&&_.validation){let T=V(_.validation,u,"");T&&y.push(`${k.label||k.key}: ${T}`)}});let $=o.$(`${o.uid}-pv-formerr`);if(y.length){$&&($.textContent=`Cannot add \u2014 ${y.length} field(s) need attention.`,$.style.display="");return}$&&($.textContent="",$.style.display="none"),e.push(d(c)),c.reset(),a=!1,l=!1,this._initDefaults(c),this._applyRules(c),this._renderTable(),this._drawChart()},deleteRow(c){e.splice(c,1),this._renderTable(),this._drawChart()},clearData(){e=[],this._renderTable(),this._drawChart()},render(){let c=o.$(`${o.uid}-panel-preview`);if(!c)return;let u=o.uid,y=s();if(!y.length){c.innerHTML='<div class="view-empty">No fields yet. Add fields on the Dialog tab.</div>';return}g();let $=`oninput="__dbb(${u}).previewView.recompute()" onchange="__dbb(${u}).previewView.recompute()"`,k=o.globalRoles||[],_=k.length?`
701
+ <label class="pv-roles">
702
+ <span class="pv-label">Preview as role</span>
703
+ <select onchange="__dbb(${u}).previewView.setPreviewRole(this.value)">
704
+ <option value="">\u2014 no role \u2014</option>
705
+ ${k.map(E=>`<option value="${m(E)}" ${E===n?"selected":""}>${m(E)}</option>`).join("")}
706
+ </select>
707
+ </label>`:"";c.innerHTML=`
708
+ <div class="pv-grid">
709
+ <div class="pv-pane">
710
+ <div class="pv-pane-head">${m(o.configName||"Dialog")}</div>
711
+ ${_}
712
+ <form class="pv-form" id="${u}-pv-form" onsubmit="return false;">
713
+ <div class="pv-fields">${y.map(E=>R(E,$)).join("")}</div>
714
+ <div class="pv-formerr" id="${u}-pv-formerr" style="display:none;"></div>
715
+ <div class="pv-actions">
716
+ <button type="button" class="pv-btn ghost" onclick="__dbb(${u}).previewView.clearData()">Clear data</button>
717
+ <button type="button" class="pv-btn" onclick="__dbb(${u}).previewView.addRow()">+ Add element</button>
718
+ </div>
719
+ </form>
720
+ </div>
721
+ <div class="pv-pane">
722
+ <div class="pv-pane-head">Data <span class="view-muted" id="${u}-pv-count"></span></div>
723
+ <div id="${u}-pv-table"></div>
724
+ <div class="pv-pane-head" style="margin-top:18px;">Chart</div>
725
+ <div class="chart-preview"><canvas id="${u}-pv-canvas"></canvas></div>
726
+ <div class="chart-note" id="${u}-pv-note">Live chart over the data you add, using the Chart tab's settings.</div>
727
+ </div>
728
+ </div>`,a=!1,l=!1;let T=o.$(`${u}-pv-form`);this._initDefaults(T),this._applyRules(T),this._renderTable(),this._drawChart()},_initDefaults(c){if(!c||a)return;a=!0,s().forEach(y=>{y.default!=null&&y.default!==""&&y.type!=="checkbox"&&y.type!=="toggle"&&f(c,y,y.default)});let u=p(c);s().forEach(y=>{let $=r[y.key];$&&$.calc&&$.calcTrigger==="onInit"&&f(c,y,V($.calc,u,""))})},_applyRules(c){if(!c)return;for(let y=0;y<4;y++){let $=p(c),k=!1;if(s().forEach(_=>{let T=r[_.key];T&&T.calc&&T.calcTrigger==="onUpdate"&&(k=f(c,_,V(T.calc,$,""))||k)}),!k)break}let u=p(c);s().forEach(y=>{let $=r[y.key]||{},k=c.querySelector(`[data-pv-key="${CSS.escape(y.key)}"]`),_=$.hidden?!!V($.hidden,u,!1):!1;k&&(k.style.display=_?"none":"");let T=($.readonly?!!V($.readonly,u,!1):!1)||!!($.calc&&$.calcTrigger==="onUpdate");if(x(c,y,T),k){let N=$.color?V($.color,u,""):"";k.style.setProperty("--pv-accent",N||"transparent"),k.classList.toggle("pv-colored",!!N),k.classList.toggle("pv-readonly",!!T)}let E=c.querySelector(`[data-pv-err="${CSS.escape(y.key)}"]`),O=l&&$.validation?V($.validation,u,""):"";E&&(E.textContent=O||""),k&&k.classList.toggle("pv-invalid",!!O)})},_renderTable(){let c=o.$(`${o.uid}-pv-table`),u=o.$(`${o.uid}-pv-count`);if(u&&(u.textContent=`\xB7 ${e.length} row(s)`),!c)return;let y=s();if(!e.length){c.innerHTML='<div class="view-empty">No data yet \u2014 fill the form and click \u201C+ Add element\u201D.</div>';return}let $=y.map(_=>`<th>${m(_.label||_.key)}</th>`).join("")+"<th></th>",k=e.map((_,T)=>`<tr>${y.map(E=>`<td>${h(_[E.key])}</td>`).join("")}<td class="pv-del-cell"><button class="pv-del" title="Delete row" onclick="__dbb(${o.uid}).previewView.deleteRow(${T})">\u2715</button></td></tr>`).join("");c.innerHTML=`<table class="view-table"><thead><tr>${$}</tr></thead><tbody>${k}</tbody></table>`},_ensureChartJs(){return typeof window<"u"&&window.Chart?Promise.resolve(window.Chart):i||(i=new Promise((c,u)=>{let y=document.createElement("script");y.src=xt,y.onload=()=>c(window.Chart),y.onerror=()=>u(new Error("Chart.js failed to load")),document.head.appendChild(y)}),i)},_drawChart(){let c=o.$(`${o.uid}-pv-canvas`);if(!c)return;let u=G(o.chartView.getSettings(),o.cards,e);this._ensureChartJs().then(y=>{c.isConnected&&(t&&(t.destroy(),t=null),t=new y(c.getContext("2d"),u))}).catch(()=>{let y=o.$(`${o.uid}-pv-note`);y&&(y.textContent="Chart.js preview unavailable (offline).")})}}}var Ct="dialog-builder";var ce="configs",_t=new Uint8Array([68,105,97,108,111,103,66,117,105,108,100,101,114,75,101,121,48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102]);function le(){return new Promise((o,e)=>{let t=indexedDB.open(Ct,1);t.onupgradeneeded=()=>{let i=t.result;i.objectStoreNames.contains(ce)||i.createObjectStore(ce,{keyPath:"key"})},t.onsuccess=()=>o(t.result),t.onerror=()=>e(t.error)})}function Se(){return typeof crypto<"u"&&crypto.subtle?crypto.subtle:null}var Ee="plain:",Te=null;function it(){return Te||(Te=Se().importKey("raw",_t,"AES-GCM",!1,["encrypt","decrypt"])),Te}function Ke(o){let e="";return o.forEach(t=>{e+=String.fromCharCode(t)}),btoa(e)}function Xe(o){return Uint8Array.from(atob(o),e=>e.charCodeAt(0))}async function Qe(o){let e=new TextEncoder().encode(JSON.stringify(o)),t=Se();if(!t)return Ee+Ke(e);let i=await it(),n=crypto.getRandomValues(new Uint8Array(12)),r=new Uint8Array(await t.encrypt({name:"AES-GCM",iv:n},i,e)),a=new Uint8Array(n.length+r.length);return a.set(n,0),a.set(r,n.length),Ke(a)}async function et(o){let e=String(o);if(e.startsWith(Ee))return JSON.parse(new TextDecoder().decode(Xe(e.slice(Ee.length))));let t=Se();if(!t)throw new Error("This config was saved with encryption, which needs a secure context (https or localhost). Open the app over https or on localhost to read it.");let i=await it(),n=Xe(e),r=n.slice(0,12),a=n.slice(12),l=await t.decrypt({name:"AES-GCM",iv:r},i,a);return JSON.parse(new TextDecoder().decode(l))}function de(o,e,t){return new Promise((i,n)=>{let r=o.transaction(ce,e),a=r.objectStore(ce),l;Promise.resolve(t(a)).then(s=>{l=s}).catch(n),r.oncomplete=()=>i(l),r.onerror=()=>n(r.error),r.onabort=()=>n(r.error)})}function tt(o){return new Promise((e,t)=>{o.onsuccess=()=>e(o.result),o.onerror=()=>t(o.error)})}function De(){return{async list(){let o=await le();return de(o,"readonly",e=>tt(e.getAllKeys()))},async save(o,e){let t=await Qe(e),i=await le();return de(i,"readwrite",n=>{n.put({key:o,encryptedValue:t})})},async load(o){let e=await le(),t=await de(e,"readonly",i=>tt(i.get(o)));return t?et(t.encryptedValue):null},async remove(o){let e=await le();return de(e,"readwrite",t=>{t.delete(o)})},encryptString(o){return Qe(o)},decryptString(o){return et(String(o).trim())}}}var kt="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js";var ue=null;function Rt(){return typeof window<"u"&&window.XLSX?Promise.resolve(window.XLSX):ue||(ue=new Promise((o,e)=>{let t=document.createElement("script");t.src=kt,t.onload=()=>o(window.XLSX),t.onerror=()=>e(new Error("Could not load the Excel parser (offline?).")),document.head.appendChild(t)}),ue)}function Tt(o){return String(o||"").toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g,(t,i)=>i.toUpperCase()).replace(/[^a-zA-Z0-9]/g,"")||"field"}function Et(o){let e="",t=o+1;for(;t>0;){let i=(t-1)%26;e=String.fromCharCode(65+i)+e,t=Math.floor((t-1)/26)}return e}var St=new Set(["true","false","yes","no"]);function Dt(o){if(typeof o=="number")return o;if(typeof o!="string")return NaN;let e=o.trim().replace(/[%$€£,\s]/g,"");return e===""?NaN:Number(e)}function At(o){let e=o.filter(i=>i!==""&&i!=null);if(!e.length)return{type:"text"};if(e.every(i=>i instanceof Date))return{type:"date"};if(e.every(i=>Number.isFinite(Dt(i))))return{type:"number"};if(e.every(i=>St.has(String(i).trim().toLowerCase())))return{type:"checkbox"};let t=[...new Set(e.map(i=>String(i).trim()))].filter(i=>i!=="");return t.length>=2&&t.length<=8&&e.length>=t.length*4?{type:"dropdown",options:t}:{type:"text"}}async function Ot(o){if(typeof DecompressionStream>"u")throw new Error("no DecompressionStream");let e=new Blob([o]).stream().pipeThrough(new DecompressionStream("deflate-raw"));return new Uint8Array(await new Response(e).arrayBuffer())}function Nt(o){let e=new Uint8Array(o),t=new DataView(o),i=-1;for(let l=e.length-22;l>=0;l--)if(t.getUint32(l,!0)===101010256){i=l;break}if(i<0)throw new Error("not a zip");let n=t.getUint16(i+10,!0),r=t.getUint32(i+16,!0),a={};for(let l=0;l<n&&t.getUint32(r,!0)===33639248;l++){let s=t.getUint16(r+10,!0),b=t.getUint32(r+20,!0),h=t.getUint16(r+28,!0),v=t.getUint16(r+30,!0),g=t.getUint16(r+32,!0),R=t.getUint32(r+42,!0),d=new TextDecoder().decode(e.subarray(r+46,r+46+h)),p=t.getUint16(R+26,!0),f=t.getUint16(R+28,!0),x=R+30+p+f;a[d]={method:s,comp:e.subarray(x,x+b)},r+=46+h+v+g}return a}function Lt(o){let e=new Set;return String(o).split(/\s+/).forEach(t=>t.split(":").forEach(i=>{let n=/([A-Za-z]+)/.exec(i);n&&e.add(n[1].toUpperCase())})),[...e]}function It(o){let e={};return(o.match(/<(?:\w+:)?dataValidation\b[\s\S]*?<\/(?:\w+:)?dataValidation>/g)||[]).forEach(i=>{if(!/type="list"/.test(i))return;let n=/sqref="([^"]*)"/.exec(i)||/<(?:\w+:)?sqref>([\s\S]*?)<\/(?:\w+:)?sqref>/.exec(i),r=/<(?:\w+:)?formula1>([\s\S]*?)<\/(?:\w+:)?formula1>/.exec(i);if(!n||!r)return;let a=r[1].trim().replace(/&quot;/g,'"').replace(/&amp;/g,"&");if(!/^".*"$/.test(a))return;let l=a.slice(1,-1).split(",").map(s=>s.trim()).filter(Boolean);l.length&&Lt(n[1]).forEach(s=>{e[s]=l})}),e}async function Ft(o){try{let e=Nt(o),t=Object.keys(e).filter(r=>/^xl\/worksheets\/sheet\d+\.xml$/i.test(r)).sort()[0];if(!t)return{};let i=e[t],n=i.method===0?i.comp:await Ot(i.comp);return It(new TextDecoder().decode(n))}catch{return{}}}async function Ae(o){let e=await Rt(),t=await o.arrayBuffer(),i=e.read(t,{type:"array",cellDates:!0}),n=i.SheetNames[0];if(!n)throw new Error("The workbook has no sheets.");let a=e.utils.sheet_to_json(i.Sheets[n],{header:1,defval:"",raw:!0}).filter(d=>d.some(p=>p!==""&&p!=null));if(!a.length)throw new Error("The first sheet is empty.");let l=await Ft(t),s=a[0].map((d,p)=>String(d).trim()||`Column ${p+1}`),b=a.slice(1),h=new Set,v=s.map((d,p)=>{let f=l[Et(p)],x=f?{type:"dropdown",options:f}:At(b.map($=>$[p])),C=Tt(d),c=C,u=1;for(;h.has(C);)C=`${c}${++u}`;h.add(C);let y={key:C,label:d,type:x.type,width:2};return x.options&&(y.options=x.options),y}),g=[];for(let d=0;d<v.length;d+=3)g.push(v.slice(d,d+3));return{name:String(o.name||"Imported").replace(/\.[^.]+$/,"")||"Imported Config",roles:[],rows:g.length?g:[[]]}}var Mt=0,Le=new Map;typeof window<"u"&&typeof window.__dbb!="function"&&(window.__dbb=o=>Le.get(o));var zt=500,qt=["https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Fira+Code&display=swap"],Oe={[D.READONLY]:{tab:"readonly",btn:"btn-readonly",icon:"lock",label:"Readonly",activeClass:"active-readonly",codeKey:"readonlyCode"},[D.HIDDEN]:{tab:"hidden",btn:"btn-hid",icon:"visibility_off",label:"Hide",activeClass:"active-hid",codeKey:"hiddenCode"},[D.OPTIONS]:{tab:"options",btn:"btn-opt",icon:"list",label:"Dropdown",activeClass:"active-opt",codeKey:"options"},[D.CALCULATION]:{tab:"calculation",btn:"btn-calc",icon:"calculate",label:"Calculation",activeClass:"active-calc",codeKey:"calculation"},[D.COLOR]:{tab:"color",btn:"btn-color",icon:"palette",label:"Color",activeClass:"active-color",codeKey:"colorCode"},[D.VALIDATION]:{tab:"validation",btn:"btn-val",icon:"bolt",label:"Validate",activeClass:"active-val",codeKey:"validationCode"},[D.EMAIL]:{tab:"email",btn:"btn-email",icon:"mail",label:"Email",activeClass:"active-email",codeKey:"emailCode"}},nt=[D.READONLY,D.HIDDEN,D.OPTIONS,D.CALCULATION,D.COLOR,D.VALIDATION,D.EMAIL],jt={readonlyCode:{btn:"btn-readonly",cls:"active-readonly"},hiddenCode:{btn:"btn-hid",cls:"active-hid"},options:{btn:"btn-opt",cls:"active-opt"},calculation:{btn:"btn-calc",cls:"active-calc"},colorCode:{btn:"btn-color",cls:"active-color"},validationCode:{btn:"btn-val",cls:"active-val"},emailCode:{btn:"btn-email",cls:"active-email"}},Vt=new Set(["key","label","type","width","row","multiple","default","options","optionsFormat","dropdownCode","readonlyCode","hiddenCode","validationCode","colorCode","calculation","calculationTrigger","emailCode","readonlyRules","hiddenRules","validationRules","colorRules","calculationRules","emailRules","readonlyRoles","hiddenRoles","readonlyFormat","hiddenFormat","readonly","hidden","validate","color","onInit","onUpdate","email","_rules"]);function Ne(){return{name:"New Dialog",roles:[],rows:[[{key:"field1",label:"Field 1",type:"text",width:2}]],workflow:{states:[{id:"s1",name:"Draft",role:"",x:40,y:40,color:"#fea20f"},{id:"s2",name:"Open",role:"",x:365.8066666666667,y:48.379999999999995,color:"#0fa216"},{id:"s3",name:"Closed",role:"",x:670,y:37,color:"#3f51b5"},{id:"s4",name:"Cancelled",role:"",x:269.36033057851216,y:141.33757575757576,color:"#f44336"}],transitions:[{from:"s1",to:"s2",role:""},{from:"s2",to:"s3",role:""},{from:"s2",to:"s4",role:""},{from:"s1",to:"s4",role:""}]}}}var K=class extends HTMLElement{constructor(){super(),this.uid=++Mt,this.attachShadow({mode:"open"}),this._handlers={},this.registry=Q(X),this.cards=[],this.globalRoles=[],this.configName="New Dialog",this.rowIds=[],this.nextRowId=0,this.nextFieldId=1,this.activeIndex=null,this._lastAnimatedIndex=null,this._draggedCardIdx=null,this._draggedRowId=null,this.openTabs={},this.deleteConfirmIdx=null,this.roleDeleteConfirm=null,this.storeDeleteConfirm=null,this.debugViewMode="active",this._pendingConfig=null,this._rendered=!1,this.activeTab="dialog",this.roleDeleteConfirm=null,this.storeDeleteConfirm=null,this.rb=Ve(this),this.tableView=ye(this),this.chartView=_e(this),this.workflowView=ke(this),this.previewView=Re(this),this.store=De()}_upgradeProperty(e){if(Object.prototype.hasOwnProperty.call(this,e)){let t=this[e];delete this[e],this[e]=t}}connectedCallback(){if(Le.set(this.uid,this),this._rendered)return;this._rendered=!0;let e=qt.map(t=>`<link rel="stylesheet" href="${t}">`).join("");if(this.shadowRoot.innerHTML=`
729
+ ${e}
730
+ <style>
731
+ .db-icon { display: inline-block; width: 1em; height: 1em; vertical-align: -0.15em; flex: none; }
732
+ ${Me}
733
+ </style>
734
+ <div class="db-root">
735
+ <div class="db-layout">
736
+ <aside class="db-sidebar">
737
+ <div class="db-sidebar-head">
738
+ <span class="db-sidebar-title">List</span>
739
+ <span class="db-sidebar-actions">
740
+ <button class="db-new-btn" onclick="__dbb(${this.uid}).importJsonClick()" title="Paste config JSON">${S("data_object",{size:14})}</button>
741
+ <button class="db-new-btn" onclick="__dbb(${this.uid}).importExcelClick()" title="Import from Excel">${S("upload_file",{size:14})}</button>
742
+ <button class="db-new-btn" onclick="__dbb(${this.uid}).exportEncrypted()" title="Export config (encrypted file)">${S("download",{size:14})}</button>
743
+ <button class="db-new-btn" onclick="__dbb(${this.uid}).importEncryptedClick()" title="Import config (encrypted file)">${S("upload",{size:14})}</button>
744
+ <button class="db-new-btn" onclick="__dbb(${this.uid}).newConfig()" title="New config">+</button>
745
+ </span>
746
+ </div>
747
+ <input type="file" id="${this.uid}-excel-input" accept=".xlsx,.xls,.csv" style="display:none" onchange="__dbb(${this.uid}).handleExcelFile(this)">
748
+ <input type="file" id="${this.uid}-enc-input" accept=".dbenc,.txt" style="display:none" onchange="__dbb(${this.uid}).handleEncryptedFile(this)">
749
+ <div class="db-store-list" id="${this.uid}-store-list"></div>
750
+ </aside>
751
+ <div class="db-main">
752
+ <div class="top-bar-config">
753
+ <div class="config-name-section">
754
+ <button class="db-save-btn" onclick="__dbb(${this.uid}).saveCurrent()" title="Save config">${S("save",{size:14})} Save</button>
755
+ <input type="text" class="config-name-input" id="${this.uid}-config-name" placeholder="Config Name"
756
+ oninput="__dbb(${this.uid}).updateConfigName(this.value)">
757
+ </div>
758
+ <div class="db-tabs" id="${this.uid}-tabs" role="tablist">
759
+ <button class="db-tab active" id="${this.uid}-tab-dialog" role="tab" onclick="__dbb(${this.uid}).setTab('dialog')">Dialog</button>
760
+ <button class="db-tab" id="${this.uid}-tab-table" role="tab" onclick="__dbb(${this.uid}).setTab('table')">Table</button>
761
+ <button class="db-tab" id="${this.uid}-tab-chart" role="tab" onclick="__dbb(${this.uid}).setTab('chart')">Chart</button>
762
+ <button class="db-tab" id="${this.uid}-tab-workflow" role="tab" onclick="__dbb(${this.uid}).setTab('workflow')">Workflow</button>
763
+ <button class="db-tab" id="${this.uid}-tab-preview" role="tab" onclick="__dbb(${this.uid}).setTab('preview')">Preview</button>
764
+ <span class="db-tab-ink" id="${this.uid}-tab-ink"></span>
765
+ </div>
766
+ <div class="roles-group">
767
+ <div class="roles-section">
768
+ <div id="${this.uid}-roles-manager" class="roles-chips-wrapper"></div>
769
+ </div>
770
+ <div class="add-role-section">
771
+ <input type="text" id="${this.uid}-new-role" placeholder="New role..." onkeydown="__dbb(${this.uid}).handleNewRoleKeydown(event)">
772
+ <button class="add-role-btn-icon" onclick="__dbb(${this.uid}).addGlobalRole()" title="Add Role">+</button>
773
+ </div>
774
+ </div>
775
+ </div>
776
+
777
+ <div class="db-panel" id="${this.uid}-panel-dialog">
778
+ <div id="${this.uid}-grids"></div>
779
+ <button class="add-row-btn" onclick="__dbb(${this.uid}).addNewRow(event)">
780
+ ${S("add")} Add Row
781
+ </button>
782
+
783
+ <div class="debug-header" id="${this.uid}-debug-header">
784
+ <div style="display:flex;gap:8px;">
785
+ <button id="${this.uid}-btn-debug-active" class="debug-tab-btn active" onclick="__dbb(${this.uid}).setDebugView('active')">Active Field JSON</button>
786
+ <button id="${this.uid}-btn-debug-dialog" class="debug-tab-btn" onclick="__dbb(${this.uid}).setDebugView('dialog')">Complete Dialog JSON</button>
787
+ </div>
788
+ </div>
789
+ <div class="debug-panel" id="${this.uid}-debug"></div>
790
+ </div>
791
+ <div class="db-panel" id="${this.uid}-panel-table" style="display:none;"></div>
792
+ <div class="db-panel" id="${this.uid}-panel-chart" style="display:none;"></div>
793
+ <div class="db-panel" id="${this.uid}-panel-workflow" style="display:none;"></div>
794
+ <div class="db-panel" id="${this.uid}-panel-preview" style="display:none;"></div>
795
+ </div>
796
+ </div>
797
+
798
+ <div class="db-modal-overlay" id="${this.uid}-json-modal" style="display:none;">
799
+ <div class="db-modal">
800
+ <div class="db-modal-head">
801
+ <span>Paste config JSON</span>
802
+ <button class="db-modal-x" onclick="__dbb(${this.uid}).closeJsonModal()" title="Close">${S("close",{size:16})}</button>
803
+ </div>
804
+ <p class="db-modal-hint">Paste a dialog config object and click Load. It replaces the current config. See <code>CONFIG_SCHEMA.md</code> for the structure.</p>
805
+ <textarea id="${this.uid}-json-input" class="db-json-input" spellcheck="false" placeholder='{
806
+ "name": "My Dialog",
807
+ "roles": ["Admin"],
808
+ "rows": [
809
+ [ { "key": "title", "label": "Title", "type": "text", "width": 6 } ]
810
+ ]
811
+ }'></textarea>
812
+ <div class="db-json-err" id="${this.uid}-json-err"></div>
813
+ <div class="db-modal-actions">
814
+ <button class="pv-btn ghost" onclick="__dbb(${this.uid}).closeJsonModal()">Cancel</button>
815
+ <button class="pv-btn" onclick="__dbb(${this.uid}).loadJsonFromText()">Load JSON</button>
816
+ </div>
817
+ </div>
818
+ </div>
819
+ </div>
820
+ `,this._upgradeProperty("fieldTypes"),this._upgradeProperty("roles"),this._upgradeProperty("config"),this._pendingConfig){let t=this._pendingConfig;this._pendingConfig=null,this._loadConfig(t)}else this._loadedOnce||this._loadConfig(Ne());this._onDocumentClick=this._onDocumentClick.bind(this),this._onWindowResize=this._onWindowResize.bind(this),document.addEventListener("click",this._onDocumentClick),window.addEventListener("resize",this._onWindowResize),requestAnimationFrame(()=>this._positionTabInk()),this.refreshStoreList()}disconnectedCallback(){Le.delete(this.uid),document.removeEventListener("click",this._onDocumentClick),window.removeEventListener("resize",this._onWindowResize)}_onDocumentClick(e){if(this.activeIndex===null||this.activeIndex===void 0)return;let t=e.composedPath(),i=t[0];if(i&&i.isConnected===!1)return;let n=this.$(`${this.uid}-card-${this.activeIndex}`);if(n&&t.includes(n))return;let r=t.find(a=>a&&a.classList&&a.classList.contains("showcase-card"));r&&r!==n||this.deselectCard()}_onWindowResize(){this._positionTabInk(),this.activeTab==="dialog"&&this.activeIndex!==null&&this.activeIndex!==void 0&&this.adjustActiveCardPosition()}setTab(e){["dialog","table","chart","workflow","preview"].includes(e)&&(this.activeTab=e,["dialog","table","chart","workflow","preview"].forEach(t=>{let i=this.$(`${this.uid}-panel-${t}`);i&&(i.style.display=t===e?"":"none");let n=this.$(`${this.uid}-tab-${t}`);n&&n.classList.toggle("active",t===e)}),this._positionTabInk(),e==="table"&&this.tableView.render(),e==="chart"&&this.chartView.render(),e==="workflow"&&this.workflowView.render(),e==="preview"&&this.previewView.render(),e==="dialog"&&this.activeIndex!==null&&this.activeIndex!==void 0&&this.adjustActiveCardPosition())}_positionTabInk(){let e=this.$(`${this.uid}-tab-ink`),t=this.$(`${this.uid}-tab-${this.activeTab}`);!e||!t||(e.style.left=`${t.offsetLeft}px`,e.style.width=`${t.offsetWidth}px`)}async refreshStoreList(){let e=this.$(`${this.uid}-store-list`);if(!e)return;let t;try{t=await this.store.list()}catch{e.innerHTML='<div class="db-store-empty">Storage unavailable.</div>';return}if(!t.length){e.innerHTML='<div class="db-store-empty">No saved configs yet.</div>';return}t.sort((i,n)=>String(i).localeCompare(String(n))),e.innerHTML=t.map(i=>`
821
+ <div class="db-store-item ${i===this.configName?"active":""} ${i===this.storeDeleteConfirm?"confirming":""}">
822
+ <button class="db-store-load" title="Load" onclick="__dbb(${this.uid}).loadFromStore('${A(i)}')">${m(i)}</button>
823
+ ${i===this.storeDeleteConfirm?`<span class="delete-confirm-wrapper"><button class="control-btn confirm-yes-btn" onclick="__dbb(${this.uid}).deleteFromStore('${A(i)}')" title="Confirm delete">Delete</button><button class="control-btn confirm-no-btn" onclick="__dbb(${this.uid}).cancelDeleteFromStore()" title="Cancel">No</button></span>`:`<button class="db-store-del" title="Delete" onclick="__dbb(${this.uid}).requestDeleteFromStore('${A(i)}')">${S("close",{size:12})}</button>`}
824
+ </div>`).join("")}importExcelClick(){let e=this.$(`${this.uid}-excel-input`);e&&(e.value="",e.click())}async handleExcelFile(e){let t=e.files&&e.files[0];if(!t)return;let i;try{i=await Ae(t)}catch(n){alert('Could not import "'+t.name+'": '+(n&&n.message?n.message:n));return}this._loadConfig(i),this.setTab("dialog"),this.notifyChange()}async exportEncrypted(){let e=(this.configName||"").trim()||"Untitled",t;try{t=await this.store.encryptString(this.getConfig())}catch(a){alert("Could not export: "+(a&&a.message?a.message:a));return}let i=new Blob([t],{type:"text/plain"}),n=URL.createObjectURL(i),r=document.createElement("a");r.href=n,r.download=`${e}.dbenc`,r.click(),URL.revokeObjectURL(n)}importEncryptedClick(){let e=this.$(`${this.uid}-enc-input`);e&&(e.value="",e.click())}async handleEncryptedFile(e){let t=e.files&&e.files[0];if(!t)return;let i;try{i=await this.store.decryptString(await t.text())}catch{alert('Could not import "'+t.name+'": the file is not a valid encrypted config.');return}this._loadConfig(i),this.setTab("dialog"),this.notifyChange()}importJsonClick(){let e=this.$(`${this.uid}-json-modal`),t=this.$(`${this.uid}-json-err`);t&&(t.textContent=""),e&&(e.style.display="");let i=this.$(`${this.uid}-json-input`);i&&i.focus()}closeJsonModal(){let e=this.$(`${this.uid}-json-modal`);e&&(e.style.display="none")}loadJsonFromText(){let e=this.$(`${this.uid}-json-input`),t=this.$(`${this.uid}-json-err`),i=a=>{t&&(t.textContent=a)};if(!e)return;let n=e.value.trim();if(!n){i("Paste a config JSON object first.");return}let r;try{r=JSON.parse(n)}catch(a){i("Invalid JSON: "+a.message);return}if(!r||typeof r!="object"||Array.isArray(r)){i('Expected a JSON object (e.g. { "name": \u2026, "rows": [ \u2026 ] }).');return}if(!Array.isArray(r.rows)){i('Config must have a "rows" array \u2014 each row is an array of field objects. See CONFIG_SCHEMA.md.');return}this._loadConfig(r),this.setTab("dialog"),this.notifyChange(),this.closeJsonModal()}newConfig(){this._loadConfig(Ne());let e=this.$(`${this.uid}-config-name`);e&&(e.focus(),e.select()),this.refreshStoreList()}async saveCurrent(){let e=(this.configName||"").trim()||"Untitled";try{await this.store.save(e,this.getConfig())}catch(t){alert("Could not save: "+(t&&t.message?t.message:t));return}await this.refreshStoreList()}async loadFromStore(e){let t;try{t=await this.store.load(e)}catch(i){alert('Could not load "'+e+'": '+(i&&i.message?i.message:i));return}t&&(this._loadConfig(t),this.refreshStoreList())}requestDeleteFromStore(e){this.storeDeleteConfirm=e,this.refreshStoreList()}cancelDeleteFromStore(){this.storeDeleteConfirm=null,this.refreshStoreList()}async deleteFromStore(e){this.storeDeleteConfirm=null;try{await this.store.remove(e)}catch(t){alert("Could not delete: "+(t&&t.message?t.message:t));return}await this.refreshStoreList()}set fieldTypes(e){this.registry=Q(e),this._rendered&&(this.renderGrids(),this.updateOutput())}get fieldTypes(){return Array.from(this.registry.values())}set config(e){if(!this._rendered){this._pendingConfig=e;return}this._loadConfig(e)}get config(){return this.getConfig()}set roles(e){this.globalRoles=Array.isArray(e)?e.slice():[],this._rendered&&(this.renderRolesManager(),this.updateOutput())}get roles(){return this.globalRoles.slice()}getConfig(){return{name:this.configName,roles:this.globalRoles.slice(),rows:this.rowIds.map(e=>this.cards.filter(t=>t.row===e).map(t=>this._exportCard(t))),chart:this.chartView.getSettings(),workflow:this.workflowView.getConfig()}}_exportCard(e){let t=JSON.parse(JSON.stringify(e)),i={key:t.key,label:t.label,type:t.type,width:t.width},n=s=>typeof s=="string"&&s.trim()!=="";t.default!=null&&t.default!==""&&(i.default=t.default),Array.isArray(t.options)&&t.options.length&&(i.options=t.options),n(t.dropdownCode)&&(i.dropdownCode=t.dropdownCode),n(t.readonlyCode)&&(i.readonly=t.readonlyCode),n(t.hiddenCode)&&(i.hidden=t.hiddenCode),n(t.validationCode)&&(i.validate=t.validationCode),n(t.colorCode)&&(i.color=t.colorCode),n(t.calculation)&&(i[t.calculationTrigger==="onUpdate"?"onUpdate":"onInit"]=t.calculation),n(t.emailCode)&&(i.email=t.emailCode),Array.isArray(t.readonlyRoles)&&t.readonlyRoles.length&&(i.readonlyRoles=t.readonlyRoles),Array.isArray(t.hiddenRoles)&&t.hiddenRoles.length&&(i.hiddenRoles=t.hiddenRoles);let r=s=>!!(s&&Array.isArray(s.rules)&&s.rules.length),a=s=>!!s&&(r(s)||s.else&&!(s.else.kind==="string"&&(s.else.value==null||s.else.value===""))),l={};return r(t.readonlyRules)&&(l.readonly=t.readonlyRules),r(t.hiddenRules)&&(l.hidden=t.hiddenRules),r(t.validationRules)&&(l.validation=t.validationRules),r(t.colorRules)&&(l.color=t.colorRules),a(t.calculationRules)&&(l.calculation=t.calculationRules),Array.isArray(t.emailRules)&&t.emailRules.length&&(l.email=t.emailRules),t.optionsFormat&&(l.optionsFormat=t.optionsFormat),Object.keys(l).length&&(i._rules=l),Object.keys(t).forEach(s=>{!Vt.has(s)&&!(s in i)&&(i[s]=t[s])}),i}$(e){return this.shadowRoot.getElementById(e)}notifyChange(){this.updateOutput(),this.activeTab==="table"?this.tableView.render():this.activeTab==="chart"?this.chartView.render():this.activeTab==="workflow"&&this.workflowView.render(),this.dispatchEvent(new CustomEvent("change",{detail:this.getConfig(),bubbles:!0,composed:!0}))}getRoles(){return this.globalRoles}getFields(){let e=[{key:"currentUserRole",label:"Current User Role",type:"text"},{key:"currentUser",label:"Current User",type:"text"}];return this.cards.forEach(t=>{let i=this.registry.get(t.type);e.push({key:t.key,label:t.label||t.key,type:t.type,multiple:t.multiple,valueBucket:i?i.valueBucket:"text"})}),e}featuresFor(e){let t=this.registry.get(e);return t?t.features:[]}firstSupportedTab(e){let t=this.featuresFor(e.type),i=nt.find(n=>t.includes(n));return i?Oe[i].tab:null}_loadConfig(e){e=e||Ne(),this._loadedOnce=!0,this.configName=typeof e.name=="string"?e.name:"New Dialog",this.globalRoles=Array.isArray(e.roles)?e.roles.slice():[];let t=[],i=[];(Array.isArray(e.rows)?e.rows:[]).forEach((l,s)=>{i.push(s),(Array.isArray(l)?l:[]).forEach(b=>{let h=this._normalizeCard(b,s);t.push(h)})}),this.cards=t,this.rowIds=i.length?i:[0],this.nextRowId=this.rowIds.length,this.cards.forEach(l=>this._syncGeneratedCode(l));let r=0;this.cards.forEach(l=>{let s=/^newField_(\d+)$/.exec(l.key||"");s&&(r=Math.max(r,Number(s[1])))}),this.nextFieldId=r+1,this.activeIndex=null,this.openTabs={},this.deleteConfirmIdx=null,this.chartView.setSettings(e.chart||{}),this.workflowView.setConfig(e.workflow||{});let a=this.$(`${this.uid}-config-name`);a&&(a.value=this.configName),this.renderGrids(),this.renderRolesManager(),this.cards.length&&this.selectCard(0),this.updateOutput()}_normalizeCard(e,t){let i=Object.assign({},e);return this._importCompactKeys(i),i.row=t,typeof i.width!="number"&&(i.width=(this.registry.get(i.type)||{}).defaultWidth||2),this.registry.has(i.type)||(i.type=this.registry.keys().next().value),(this.registry.get(i.type)||{}).multiple?i.multiple=!0:delete i.multiple,Array.isArray(i.readonlyRoles)||(i.readonlyRoles=[]),Array.isArray(i.hiddenRoles)||(i.hiddenRoles=[]),Array.isArray(i.options)||(i.options=[]),this._syncGeneratedCode(i),i}_importCompactKeys(e){if(e._rules&&typeof e._rules=="object"){let i=e._rules;i.readonly&&!e.readonlyRules&&(e.readonlyRules=i.readonly),i.hidden&&!e.hiddenRules&&(e.hiddenRules=i.hidden),i.validation&&!e.validationRules&&(e.validationRules=i.validation),i.color&&!e.colorRules&&(e.colorRules=i.color),i.calculation&&!e.calculationRules&&(e.calculationRules=i.calculation),i.email&&!e.emailRules&&(e.emailRules=i.email),i.optionsFormat&&!e.optionsFormat&&(e.optionsFormat=i.optionsFormat),delete e._rules}let t=(i,n)=>{typeof e[i]=="string"&&e[i].trim()&&!e[n]?e[n]=e[i]:e[i]===!0&&!e[n]&&(e[n]="x => true"),i in e&&delete e[i]};t("readonly","readonlyCode"),t("disabled","readonlyCode"),t("hidden","hiddenCode"),t("validate","validationCode"),t("color","colorCode"),t("email","emailCode"),typeof e.onInit=="string"&&e.onInit.trim()&&!e.calculation&&(e.calculation=e.onInit,e.calculationTrigger="onInit"),delete e.onInit,typeof e.onUpdate=="string"&&e.onUpdate.trim()&&!e.calculation&&(e.calculation=e.onUpdate,e.calculationTrigger="onUpdate"),delete e.onUpdate,delete e.readonlyFormat,delete e.hiddenFormat}_syncGeneratedCode(e){let t=this.getFields();if(e.readonlyRules||e.readonlyRoles&&e.readonlyRoles.length>0){let i=e.readonlyRules&&e.readonlyRules.rules.length>0||e.readonlyRoles&&e.readonlyRoles.length>0;e.readonlyCode=i?I(t,e.readonlyRules||{rules:[]},"false",e.readonlyRoles):e.readonlyCode||""}if(e.hiddenRules||e.hiddenRoles&&e.hiddenRoles.length>0){let i=e.hiddenRules&&e.hiddenRules.rules.length>0||e.hiddenRoles&&e.hiddenRoles.length>0;e.hiddenCode=i?I(t,e.hiddenRules||{rules:[]},"false",e.hiddenRoles):e.hiddenCode||""}if(e.calculationRules){let i=e.calculationRules.else,n=e.calculationRules.rules.length>0||i&&!(i.kind==="string"&&(i.value==null||i.value===""));e.calculation=n?z(t,e.calculationRules):e.calculation||""}if(e.validationRules&&(e.validationCode=e.validationRules.rules.length>0?M(t,e.validationRules):e.validationCode||""),e.colorRules){let i=e.colorRules.rules.length>0;e.colorCode=i?q(t,e.colorRules):e.colorCode||""}Array.isArray(e.emailRules)&&(this._normalizeEmailRules(e),e.emailCode=this._emailConfigured(e)?oe(t,e.emailRules):e.emailCode||"")}renderRolesManager(){let e=this.$(`${this.uid}-roles-manager`);if(e){if(this.globalRoles.length===0){e.innerHTML='<div style="font-size:12px;color:var(--db-text-muted);font-style:italic;">No roles</div>';return}e.innerHTML=this.globalRoles.map(t=>`
825
+ <div class="role-chip ${this.roleDeleteConfirm===t?"confirming":""}">
826
+ <span>${m(t)}</span>
827
+ ${this.roleDeleteConfirm===t?`<span class="delete-confirm-wrapper"><button class="control-btn confirm-yes-btn" onclick="__dbb(${this.uid}).deleteGlobalRole('${A(t)}')" title="Confirm delete">Delete</button><button class="control-btn confirm-no-btn" onclick="__dbb(${this.uid}).cancelDeleteGlobalRole()" title="Cancel">No</button></span>`:`<button class="delete-role-btn" onclick="__dbb(${this.uid}).requestDeleteGlobalRole('${A(t)}')" title="Delete role">${S("close",{size:12})}</button>`}
828
+ </div>`).join("")}}updateConfigName(e){this.configName=e,this.notifyChange()}addGlobalRole(){let e=this.$(`${this.uid}-new-role`);if(!e)return;let t=e.value.trim();if(t){if(!/^[a-zA-Z0-9_\-\s]+$/.test(t)){alert("Role name must be alphanumeric.");return}if(this.globalRoles.includes(t)){alert("Role name already exists.");return}this.globalRoles.push(t),e.value="",this.renderRolesManager(),this.activeIndex!==null&&(this.openTabs[this.activeIndex]==="readonly"||this.openTabs[this.activeIndex]==="hidden")&&this.renderDrawerContent(this.activeIndex,this.openTabs[this.activeIndex]),this.notifyChange()}}requestDeleteGlobalRole(e){this.roleDeleteConfirm=e,this.renderRolesManager()}cancelDeleteGlobalRole(){this.roleDeleteConfirm=null,this.renderRolesManager()}deleteGlobalRole(e){this.roleDeleteConfirm=null,this.globalRoles=this.globalRoles.filter(t=>t!==e),this.cards.forEach((t,i)=>{let n=!1;["readonlyRoles","hiddenRoles"].forEach(r=>{t[r]&&t[r].includes(e)&&(t[r]=t[r].filter(a=>a!==e),n=!0)}),n&&(t.readonlyRules&&this.rb.commit(i,"readonly"),t.hiddenRules&&this.rb.commit(i,"hidden"))}),this.renderRolesManager(),this.activeIndex!==null&&(this.openTabs[this.activeIndex]==="readonly"||this.openTabs[this.activeIndex]==="hidden")&&this.renderDrawerContent(this.activeIndex,this.openTabs[this.activeIndex]),this.notifyChange()}handleNewRoleKeydown(e){e.key==="Enter"&&this.addGlobalRole()}toggleFieldRole(e,t,i,n){let r=this.cards[e],a=t==="readonly"?"readonlyRoles":"hiddenRoles";r[a]||(r[a]=[]),n?r[a].includes(i)||r[a].push(i):r[a]=r[a].filter(l=>l!==i),this.rb.commit(e,t)}renderRolesCheckboxes(e,t){let r=this.cards[e][t==="readonly"?"readonlyRoles":"hiddenRoles"]||[];if(this.globalRoles.length===0)return'<div class="drawer-roles-section"><div class="drawer-roles-title">Role-based Restriction</div><div style="font-size:12px;color:var(--db-text-muted);font-style:italic;">No roles defined. Add roles at the top first.</div></div>';let a=this.globalRoles.map(l=>`
829
+ <label class="drawer-role-item">
830
+ <input type="checkbox" ${r.includes(l)?"checked":""} onchange="__dbb(${this.uid}).toggleFieldRole(${e}, '${t}', '${A(l)}', this.checked)">
831
+ <span>${m(l)}</span>
832
+ </label>`).join("");return`<div class="drawer-roles-section"><div class="drawer-roles-title">${t==="readonly"?"Readonly":"Hidden"} for Roles</div><div class="drawer-roles-list">${a}</div></div>`}setDebugView(e){this.debugViewMode=e,this.$(`${this.uid}-btn-debug-active`).classList.toggle("active",e==="active"),this.$(`${this.uid}-btn-debug-dialog`).classList.toggle("active",e==="dialog"),this.updateOutput()}updateOutput(){this._applyDevModeVisibility();let e=this.$(`${this.uid}-debug`);if(!e)return;if(this.debugViewMode==="active"){e.textContent=this.activeIndex!==null?JSON.stringify(this._exportCard(this.cards[this.activeIndex]),null,2):"";return}let t=this.$(`${this.uid}-debug-json`);t||(e.innerHTML=`
833
+ <div class="debug-edit-bar">
834
+ <span class="debug-edit-err" id="${this.uid}-debug-json-err"></span>
835
+ <button class="debug-tab-btn" onclick="__dbb(${this.uid}).applyDebugJson()">Apply</button>
836
+ </div>
837
+ <textarea class="debug-edit-area" id="${this.uid}-debug-json" spellcheck="false"></textarea>`,t=this.$(`${this.uid}-debug-json`)),this.shadowRoot.activeElement!==t&&(t.value=JSON.stringify(this.getConfig(),null,2))}applyDebugJson(){let e=this.$(`${this.uid}-debug-json`),t=this.$(`${this.uid}-debug-json-err`);if(!e)return;let i=r=>{t&&(t.textContent=r)},n;try{n=JSON.parse(e.value)}catch(r){i("Invalid JSON: "+r.message);return}if(!n||typeof n!="object"||Array.isArray(n)||!Array.isArray(n.rows)){i('Config must be an object with a "rows" array.');return}t&&(t.textContent=""),this._loadConfig(n),this.notifyChange()}_devModeOn(){let e=this.rowIds[0],t=this.cards.find(i=>i.row===e)||this.cards[0];return!!t&&(t.label==="DevMode"||t.key==="DevMode")}_applyDevModeVisibility(){let e=this._devModeOn(),t=this.$(`${this.uid}-debug-header`),i=this.$(`${this.uid}-debug`);t&&(t.style.display=e?"":"none"),i&&(i.style.display=e?"":"none")}getScaleClassForWidth(e){return e<=2?"scale-lg":e<=4?"scale-md":"scale-sm"}renderGrids(){let e=this.$(`${this.uid}-grids`);if(!e)return;let t=this.uid,i="";if(this.rowIds.forEach(n=>{let r=this.cards.filter(s=>s.row===n),a=r.reduce((s,b)=>s+b.width,0),l=a>0?`repeat(${a}, 1fr) 36px`:"36px";i+=`
838
+ <div class="db-row" id="${t}-row-${n}" draggable="true"
839
+ ondragstart="__dbb(${t}).handleRowDragStart(event, ${n})"
840
+ ondragover="__dbb(${t}).handleRowDragOver(event, ${n})"
841
+ ondragleave="__dbb(${t}).handleRowDragLeave(event, ${n})"
842
+ ondrop="__dbb(${t}).handleRowDrop(event, ${n})"
843
+ ondragend="__dbb(${t}).handleRowDragEnd(event)">
844
+ <div class="row-drag-handle" title="Drag to reorder row">${S("drag_indicator",{size:18})}</div>
845
+ <div class="showcase-grid-wrapper"
846
+ ondragover="__dbb(${t}).handleGridDragOver(event, ${n})"
847
+ ondrop="__dbb(${t}).handleGridDrop(event, ${n})">
848
+ <div class="showcase-grid" id="${t}-grid-${n}" style="--grid-template:${l};">
849
+ ${r.map(s=>this.renderCard(s,this.cards.indexOf(s))).join("")}
850
+ <div class="add-card-placeholder" onclick="__dbb(${t}).addNewCard(${n}, event)" title="Add Element">
851
+ <div class="add-card-inner">${S("add",{size:18})}</div>
852
+ </div>
853
+ </div>
854
+ </div>
855
+ </div>`}),e.innerHTML=i,this.activeIndex!==null&&this.openTabs[this.activeIndex]){let n=this.$(`${t}-drawer-${this.activeIndex}`);n&&(n.style.display="flex"),this.renderDrawerContent(this.activeIndex,this.openTabs[this.activeIndex])}this.floatActiveCard()}floatActiveCard(){let e=this.uid;if(this.activeIndex===null||this.activeIndex===void 0){this._lastAnimatedIndex=null;return}let t=this.$(`${e}-card-${this.activeIndex}`);if(!t){this._lastAnimatedIndex=null;return}if(this._lastAnimatedIndex!==this.activeIndex){let n=t.querySelector(".card-inner"),r=this.getScaleClassForWidth(this.cards[this.activeIndex].width);this.adjustActiveCardPosition(),n&&(n.style.transition="none",t.classList.remove("active","scale-sm","scale-md","scale-lg"),n.offsetHeight,n.style.transition=""),t.classList.add("active",r)}else this.adjustActiveCardPosition();this._lastAnimatedIndex=this.activeIndex}_activeMinWidth(){let e=getComputedStyle(this).getPropertyValue("--db-active-min-width"),t=parseFloat(e);return Number.isFinite(t)&&t>0?t:zt}adjustActiveCardPosition(){let e=this.uid;for(let h=0;h<this.cards.length;h++){if(h===this.activeIndex)continue;let v=this.$(`${e}-card-${h}`),g=v&&v.querySelector(".card-inner");g&&(v.style.height="",g.style.position="",g.style.left="",g.style.top="",g.style.width="",g.style.boxSizing="")}if(this.activeIndex===null||this.activeIndex===void 0)return;let t=this.$(`${e}-card-${this.activeIndex}`);if(!t)return;let i=t.querySelector(".card-inner");if(!i)return;let n=t.getBoundingClientRect(),r=Math.max(this._activeMinWidth(),n.width),a=i.querySelector(".card-drawer"),l="";a&&(l=a.style.display,a.style.display="none"),i.style.position="absolute",i.style.width=`${r}px`,i.style.boxSizing="border-box",i.style.visibility="hidden",i.style.height="auto";let s=i.offsetHeight;a&&(a.style.display=l),i.style.visibility="",i.style.height="",t.style.height=`${s}px`;let b=t.closest(".showcase-grid");if(b){let h=b.getBoundingClientRect(),v=b.querySelector(".add-card-placeholder"),g=v?v.getBoundingClientRect().left:h.right,R=(n.width-r)/2,d=h.left-n.left+16,p=g-n.left-20;R<d&&(R=d),R+r>p&&(R=p-r),i.style.position="absolute",i.style.top="0px",i.style.left=`${R}px`,i.style.width=`${r}px`,i.style.boxSizing="border-box"}}renderCard(e,t){let i=this.uid,n=t===this.activeIndex,r=this.featuresFor(e.type),a=this.getScaleClassForWidth(e.width),l=e.calculationTrigger==="onUpdate"&&e.calculation&&e.calculation.trim()!=="",s={[D.READONLY]:e.readonlyCode&&e.readonlyCode.trim()!==""||e.readonlyRoles&&e.readonlyRoles.length>0||l,[D.HIDDEN]:e.hiddenCode&&e.hiddenCode.trim()!==""||e.hiddenRoles&&e.hiddenRoles.length>0,[D.OPTIONS]:e.options&&e.options.length>0||e.dropdownCode&&e.dropdownCode.trim()!=="",[D.CALCULATION]:e.calculation&&e.calculation.trim()!=="",[D.COLOR]:e.colorCode&&e.colorCode.trim()!=="",[D.VALIDATION]:e.validationCode&&e.validationCode.trim()!=="",[D.EMAIL]:e.emailCode&&e.emailCode.trim()!==""||e.emailRules&&e.emailRules.length>0},b=Array.from(this.registry.values()).map(v=>`<option value="${v.value}" ${e.type===v.value?"selected":""}>${m(v.label)}</option>`).join(""),h=nt.filter(v=>r.includes(v)).map(v=>{let g=Oe[v],R=s[v]?`active ${g.activeClass}`:"",d=this.openTabs[t]===g.tab?"tab-open":"";return`<button class="status-btn ${R} ${d}" onclick="__dbb(${i}).openComplexTab(${t}, '${g.tab}', event)" id="${i}-${g.btn}-${t}" title="Edit ${g.label}">
856
+ ${S(g.icon,{size:18})}<span>${g.label}</span>
857
+ </button>`}).join("");return`
858
+ <div class="showcase-card ${n?"active "+a:""}" id="${i}-card-${t}" onclick="__dbb(${i}).selectCard(${t})" onkeydown="__dbb(${i}).handleCardKeydown(${t}, event)" style="--card-width:${e.width};"
859
+ draggable="true"
860
+ ondragstart="__dbb(${i}).handleCardDragStart(event, ${t})"
861
+ ondragover="__dbb(${i}).handleCardDragOver(event, ${t})"
862
+ ondragleave="__dbb(${i}).handleCardDragLeave(event, ${t})"
863
+ ondrop="__dbb(${i}).handleCardDrop(event, ${t})"
864
+ ondragend="__dbb(${i}).handleCardDragEnd(event)">
865
+ <div class="card-inner">
866
+ <div class="inputElementText">
867
+ <div class="lable">
868
+ <input type="text" id="${i}-label-${t}" value="${m(e.label||"")}" placeholder="Label" oninput="__dbb(${i}).handleLabelInput(${t}, event)">
869
+ </div>
870
+ <select class="type" id="${i}-type-${t}" onchange="__dbb(${i}).handleTypeChange(${t}, event)">${b}</select>
871
+ </div>
872
+ ${l?`<div class="calc-ro-note">${S("lock",{size:14})}<span>Read-only \u2014 value set by calculation on update</span></div>`:""}
873
+ <div class="card-footer-row">
874
+ <div class="controls-row">
875
+ <div class="width-adjust-box">
876
+ <button onclick="__dbb(${i}).adjustWidth(${t}, -1, event)">-</button>
877
+ <span>w: <span class="width-value" id="${i}-width-${t}">${e.width}</span></span>
878
+ <button onclick="__dbb(${i}).adjustWidth(${t}, 1, event)">+</button>
879
+ </div>
880
+ <button class="control-btn copy-btn" onclick="__dbb(${i}).copyCard(${t}, event)" title="Copy Element">${S("content_copy",{size:16})}</button>
881
+ ${this.deleteConfirmIdx===t?`<span class="delete-confirm-wrapper"><button class="control-btn confirm-yes-btn" onclick="__dbb(${i}).confirmDeleteCard(${t}, event)" title="Confirm Delete">Delete</button><button class="control-btn confirm-no-btn" onclick="__dbb(${i}).cancelDeleteCard(event)" title="Cancel">No</button></span>`:`<button class="control-btn delete-btn" onclick="__dbb(${i}).requestDeleteCard(${t}, event)" title="Delete Element">${S("delete",{size:16})}</button>`}
882
+ </div>
883
+ <div class="card-status-strip">${h}</div>
884
+ </div>
885
+ <div class="card-drawer" id="${i}-drawer-${t}" style="display:none;"></div>
886
+ </div>
887
+ </div>`}selectCard(e){if(!(this.activeIndex===e&&this.deleteConfirmIdx===null)){if(this.deleteConfirmIdx=null,this.activeIndex=e,Object.keys(this.openTabs).forEach(t=>{Number(t)!==e&&delete this.openTabs[t]}),!this.openTabs[e]){let t=this.firstSupportedTab(this.cards[e]);t&&(this.openTabs[e]=t)}this.renderGrids(),this.updateOutput()}}deselectCard(){this.activeIndex=null,this.deleteConfirmIdx=null,this.openTabs={},this.renderGrids(),this.updateOutput()}handleCardKeydown(e,t){if(t.target.closest&&t.target.closest(".card-drawer"))return;let i=t.target.tagName;if(t.key==="Enter"){if(i==="BUTTON"||i==="TEXTAREA")return;t.preventDefault(),t.stopPropagation(),this.addNewCard(this.cards[e].row,t)}else t.key==="Tab"&&t.target.id===`${this.uid}-label-${e}`&&(t.preventDefault(),t.stopPropagation(),this.focusAdjacentCard(e,t.shiftKey?-1:1))}_visualCardOrder(){let e=[];return this.rowIds.forEach(t=>{this.cards.forEach((i,n)=>{i.row===t&&e.push(n)})}),e}focusAdjacentCard(e,t){let i=this._visualCardOrder(),n=i.indexOf(e);n===-1||i.length<2||this.focusCard(i[(n+t+i.length)%i.length])}focusCard(e){this.selectCard(e),setTimeout(()=>{let t=this.$(`${this.uid}-label-${e}`);t&&(t.focus(),t.select())},50)}openComplexTab(e,t,i){i&&i.stopPropagation(),this.activeIndex!==e&&(this.activeIndex=e,this.deleteConfirmIdx=null),this.openTabs[e]===t?delete this.openTabs[e]:(Object.keys(this.openTabs).forEach(n=>delete this.openTabs[n]),this.openTabs[e]=t),this.renderGrids(),this.updateOutput()}getOptionsFormat(e){return e.optionsFormat||(e.dropdownCode?"api":e.options&&e.options.length>0&&typeof e.options[0]=="object"?"object":"string")}renderDrawerContent(e,t){let i=this.uid,n=this.$(`${i}-drawer-${e}`);if(!n)return;let r=this.cards[e];if(t==="readonly")n.innerHTML=`<div class="drawer-title">Readonly Script</div>${this.renderRolesCheckboxes(e,"readonly")}<div class="rb-host" id="${this.rb.hostId(e,"readonly")}"></div>`,this.rb.show(e,"readonly");else if(t==="hidden")n.innerHTML=`<div class="drawer-title">Hidden Script</div>${this.renderRolesCheckboxes(e,"hidden")}<div class="rb-host" id="${this.rb.hostId(e,"hidden")}"></div>`,this.rb.show(e,"hidden");else if(t==="calculation")n.innerHTML=`<div class="drawer-title">Calculation Script</div><div class="rb-host" id="${this.rb.hostId(e,"calculation")}"></div>`,this.rb.show(e,"calculation");else if(t==="color")n.innerHTML=`<div class="drawer-title">Color Rule</div><div class="rb-host" id="${this.rb.hostId(e,"color")}"></div>`,this.rb.show(e,"color");else if(t==="email")this.renderEmailDrawer(e);else if(t==="validation")n.innerHTML=`<div class="drawer-title">Validation Script</div><div class="rb-host" id="${this.rb.hostId(e,"validation")}"></div>`,this.rb.show(e,"validation");else if(t==="options"){let a=this.getOptionsFormat(r);n.innerHTML=`
888
+ <div class="drawer-title">Dropdown Options</div>
889
+ <div class="format-selector">
890
+ <button class="format-btn ${a==="string"?"active":""}" onclick="__dbb(${i}).setOptionsFormat(${e}, 'string')">Value</button>
891
+ <button class="format-btn ${a==="object"?"active":""}" onclick="__dbb(${i}).setOptionsFormat(${e}, 'object')">Table</button>
892
+ <button class="format-btn ${a==="api"?"active":""}" onclick="__dbb(${i}).setOptionsFormat(${e}, 'api')">API</button>
893
+ </div>
894
+ <div id="${i}-opt-list-${e}"></div>
895
+ <div class="add-opt-row" id="${i}-add-opt-row-${e}">
896
+ <input type="text" placeholder="${a==="string"?"Add option (Enter / paste rows)...":"Add row: val, label..."}" id="${i}-new-opt-${e}" onkeydown="__dbb(${i}).handleOptionInputKeydown(${e}, event)" onpaste="__dbb(${i}).handleOptionInputPaste(${e}, event)">
897
+ <button onclick="__dbb(${i}).addFieldOption(${e})" class="add-opt-btn">+</button>
898
+ </div>`,this.updateOptionsDrawerContent(e)}}setOptionsFormat(e,t){let i=this.cards[e];if(this.getOptionsFormat(i)!==t){if(i.optionsFormat=t,i.optionColumns=i.optionColumns||["value","label"],t==="api")(!i.dropdownCode||i.dropdownCode.trim()==="")&&(i.dropdownCode="async x => { return []; }");else if(t==="string")i.options=(i.options||[]).map(r=>r&&typeof r=="object"?r.label||r.value||JSON.stringify(r):String(r));else{let r=i.optionColumns;i.options=(i.options||[]).map(a=>{if(a&&typeof a=="object")return a;let l={};return r.forEach(s=>{l[s]=String(a)}),l})}this.renderDrawerContent(e,"options"),this.notifyChange()}}handleOptionInputKeydown(e,t){t.key==="Enter"&&(t.preventDefault(),this.addFieldOption(e))}handleOptionInputPaste(e,t){let i=(t.clipboardData||window.clipboardData).getData("text");if(!(i.includes(`
899
+ `)||i.includes(" ")||i.includes("\r")))return;t.preventDefault();let n=this.cards[e];n.options||(n.options=[]);let r=i.split(/\r?\n/).map(a=>a.trim()).filter(a=>a.length>0);if(this.getOptionsFormat(n)==="string")r.forEach(a=>a.split(" ").map(l=>l.trim()).filter(l=>l.length>0).forEach(l=>n.options.push(l)));else{let a=n.optionColumns||["value","label"];r.forEach(l=>{let s=l.split(" ").map(h=>h.trim()),b={};a.forEach((h,v)=>{b[h]=s[v]!==void 0?s[v]:s[0]||""}),n.options.push(b)})}t.target.value="",this.updateOptionsDrawerContent(e)}updateOptionsDrawerContent(e){let t=this.uid,i=this.$(`${t}-opt-list-${e}`),n=this.cards[e];if(!i)return;let r=this.getOptionsFormat(n),a=this.$(`${t}-add-opt-row-${e}`);if(a&&(a.style.display=r==="api"?"none":"flex"),r==="string")i.innerHTML=(n.options||[]).map((s,b)=>`
900
+ <div class="opt-string-row">
901
+ <input type="text" value="${m(s)}" oninput="__dbb(${t}).updateFieldOption(${e}, ${b}, this.value)">
902
+ <button class="opt-del" onclick="__dbb(${t}).removeFieldOption(${e}, ${b}, event)">\xD7</button>
903
+ </div>`).join("");else if(r==="object"){let s=n.optionColumns||["value","label"],b=n.options||[];i.innerHTML=`<table class="options-table">
904
+ <thead><tr>${s.map((h,v)=>`<th><input type="text" value="${m(h)}" oninput="__dbb(${t}).updateOptionColumn(${e}, ${v}, this.value)" style="font-weight:bold;border:none;background:transparent;width:60px;"></th>`).join("")}<th style="width:8px;"></th></tr></thead>
905
+ <tbody>${b.map((h,v)=>{let g=typeof h=="object"?h:{};return`<tr>${s.map(R=>`<td><input type="text" value="${m(g[R]||"")}" oninput="__dbb(${t}).updateFieldObjectProperty(${e}, ${v}, '${A(R)}', this.value)" style="border:none;width:100%;background:transparent;"></td>`).join("")}<td style="text-align:center;"><button class="opt-del" onclick="__dbb(${t}).removeFieldOption(${e}, ${v}, event)">\xD7</button></td></tr>`}).join("")}</tbody>
906
+ </table>`}else i.innerHTML=`<div style="margin-top:4px;"><div class="drawer-title" style="margin-bottom:4px;">Fetcher Script</div>
907
+ <textarea rows="3" style="font-family:monospace;font-size:11px;width:100%;" oninput="__dbb(${t}).updateFieldString(${e}, 'dropdownCode', this.value)" placeholder="async x => { return []; }">${m(n.dropdownCode||"")}</textarea></div>`;let l=r==="api"?n.dropdownCode&&n.dropdownCode.trim()!=="":n.options&&n.options.length>0;this.updateButtonVisuals(e,"options",l),this.notifyChange()}updateFieldOption(e,t,i){this.cards[e].options[t]=i,this.notifyChange()}updateOptionColumn(e,t,i){let n=this.cards[e],r=n.optionColumns[t];n.optionColumns[t]=i,(n.options||[]).forEach(a=>{a&&typeof a=="object"&&(a[i]=a[r],delete a[r])}),this.notifyChange()}updateFieldObjectProperty(e,t,i,n){let r=this.cards[e];(!r.options[t]||typeof r.options[t]!="object")&&(r.options[t]={}),r.options[t][i]=n,this.notifyChange()}addFieldOption(e){let t=this.$(`${this.uid}-new-opt-${e}`),i=t.value.trim();if(!i)return;let n=this.cards[e];if(n.options||(n.options=[]),this.getOptionsFormat(n)==="string")n.options.push(i);else{let r=n.optionColumns||["value","label"],a={},l=i.split(/[,\t]/).map(s=>s.trim());r.forEach((s,b)=>{a[s]=l[b]||l[0]||""}),n.options.push(a)}t.value="",this.updateOptionsDrawerContent(e)}removeFieldOption(e,t,i){i&&i.stopPropagation(),this.cards[e].options.splice(t,1),this.updateOptionsDrawerContent(e)}updateFieldString(e,t,i){let n=this.cards[e];n[t]=i;let r=i.trim()!=="";t==="dropdownCode"&&this.updateButtonVisuals(e,"options",r),this.notifyChange()}_emailConfigured(e){return Array.isArray(e.emailRules)&&e.emailRules.some(t=>t&&(t.recipientType==="role"?t.role:t.field)&&Array.isArray(t.conditions)&&t.conditions.some(i=>i.field))}_emailRecipientFields(e){return this.cards.filter(t=>t!==e&&["text","dropdown","dropdownList"].includes(t.type))}_cardByKey(e){return this.cards.find(t=>t.key===e)}_optionValuesForCard(e){if(!e||!this.featuresFor(e.type).includes(D.OPTIONS))return null;let t=e.options||[];return t.length?t.map(i=>{if(i&&typeof i=="object"){let n=i.value!=null?i.value:i.label!=null?i.label:"";return{value:String(n),label:String(i.label!=null?i.label:n)}}return{value:String(i),label:String(i)}}):null}_newEmailCond(e){return{field:e.key,kind:"changedTo",value:""}}_normalizeEmailRules(e){Array.isArray(e.emailRules)&&e.emailRules.forEach(t=>{if(!Array.isArray(t.conditions)){let i=[];t.from!==void 0&&t.from!==""&&i.push({field:e.key,kind:"changedFrom",value:t.from}),t.to!==void 0&&t.to!==""&&i.push({field:e.key,kind:"changedTo",value:t.to}),i.length||i.push(this._newEmailCond(e)),t.conditions=i,delete t.from,delete t.to}})}renderEmailDrawer(e){let t=this.uid,i=this.$(`${t}-drawer-${e}`);if(!i)return;let n=this.cards[e];Array.isArray(n.emailRules)||(n.emailRules=[]),this._normalizeEmailRules(n);let r=n.emailRules,a=this._emailRecipientFields(n),l=this.globalRoles,s=[["changedFrom","changed from"],["is","is"],["changedTo","changed to"]],b=(g,R,d)=>{let p=this._optionValuesForCard(this._cardByKey(d.field));return p?`<select class="email-val" onchange="__dbb(${t}).setEmailCondValue(${e}, ${g}, ${R}, this.value)">
908
+ <option value="">(any)</option>
909
+ ${p.map(f=>`<option value="${m(f.value)}" ${f.value===(d.value||"")?"selected":""}>${m(f.label)}</option>`).join("")}
910
+ </select>`:`<input class="email-val" type="text" value="${m(d.value||"")}" placeholder="value" oninput="__dbb(${t}).setEmailCondValue(${e}, ${g}, ${R}, this.value)">`},h=(g,R,d,p)=>{let f=`<select class="email-val" onchange="__dbb(${t}).setEmailCondField(${e}, ${g}, ${R}, this.value)">${this.cards.map(c=>`<option value="${m(c.key)}" ${c.key===d.field?"selected":""}>${m(c.label||c.key)}</option>`).join("")}</select>`,x=`<select class="email-kind" onchange="__dbb(${t}).setEmailCondKind(${e}, ${g}, ${R}, this.value)">${s.map(([c,u])=>`<option value="${c}" ${c===(d.kind||"changedTo")?"selected":""}>${u}</option>`).join("")}</select>`,C=p?`<button class="rb-x" title="Remove condition" onclick="__dbb(${t}).removeEmailCond(${e}, ${g}, ${R})">\u2715</button>`:"";return`<div class="email-cond"><div class="email-cond-r1">${f}</div><div class="email-cond-r2">${x}${b(g,R,d)}${C}</div></div>`},v=r.map((g,R)=>{let d=g.recipientType==="role"?"role":"field",p=(g.conditions||[]).map((x,C)=>(C>0?'<div class="email-and">AND</div>':"")+h(R,C,x,g.conditions.length>1)).join(""),f=d==="role"?l.length?`<select class="email-val" onchange="__dbb(${t}).setEmailRole(${e}, ${R}, this.value)"><option value="">-- role --</option>${l.map(x=>`<option value="${m(x)}" ${x===g.role?"selected":""}>${m(x)}</option>`).join("")}</select>`:'<span class="email-note">No roles defined. Add roles at the top first.</span>':a.length?`<select class="email-val" onchange="__dbb(${t}).setEmailField(${e}, ${R}, this.value)"><option value="">-- field --</option>${a.map(x=>`<option value="${m(x.key)}" ${x.key===g.field?"selected":""}>${m(x.label||x.key)}</option>`).join("")}</select>`:'<span class="email-note">No other text/select fields to send to.</span>';return`<div class="email-rule">
911
+ <div class="email-head">
912
+ <span class="email-idx">Rule ${R+1}</span><span class="rb-spacer"></span>
913
+ <button class="control-btn delete-btn" title="Delete rule" onclick="__dbb(${t}).removeEmailRule(${e}, ${R})">${S("delete",{size:16})}</button>
914
+ </div>
915
+ <div class="email-kw">WHEN</div>
916
+ ${p}
917
+ <button class="rb-add" onclick="__dbb(${t}).addEmailCond(${e}, ${R})">+ condition</button>
918
+ <div class="email-row">
919
+ <span class="email-kw">SEND TO</span>
920
+ <span class="rb-rhsmode">
921
+ <button class="${d==="field"?"on":""}" onclick="__dbb(${t}).setEmailRecipientType(${e}, ${R}, 'field')">Field</button>
922
+ <button class="${d==="role"?"on":""}" onclick="__dbb(${t}).setEmailRecipientType(${e}, ${R}, 'role')">Role</button>
923
+ </span>
924
+ ${f}
925
+ </div>
926
+ </div>`}).join("");i.innerHTML=`<div class="drawer-title">Email on Change</div>
927
+ <div class="email-hint">Notify another field's value (text / select / multi-select) or a role when all conditions hold. Each condition checks a field's value: "changed from", "is", or "changed to".</div>
928
+ ${v}
929
+ <button class="rb-addrule" onclick="__dbb(${t}).addEmailRule(${e})">+ Add email rule</button>`}addEmailRule(e){let t=this.cards[e];Array.isArray(t.emailRules)||(t.emailRules=[]),t.emailRules.push({conditions:[this._newEmailCond(t)],recipientType:"field",field:"",role:""}),this.renderEmailDrawer(e),this._commitEmail(e)}removeEmailRule(e,t){this.cards[e].emailRules.splice(t,1),this.renderEmailDrawer(e),this._commitEmail(e)}addEmailCond(e,t){let i=this.cards[e];i.emailRules[t].conditions.push(this._newEmailCond(i)),this.renderEmailDrawer(e),this._commitEmail(e)}removeEmailCond(e,t,i){let n=this.cards[e].emailRules[t].conditions;n.splice(i,1),n.length||n.push(this._newEmailCond(this.cards[e])),this.renderEmailDrawer(e),this._commitEmail(e)}setEmailCondField(e,t,i,n){this.cards[e].emailRules[t].conditions[i].field=n,this.renderEmailDrawer(e),this._commitEmail(e)}setEmailCondKind(e,t,i,n){this.cards[e].emailRules[t].conditions[i].kind=n,this._commitEmail(e)}setEmailCondValue(e,t,i,n){this.cards[e].emailRules[t].conditions[i].value=n,this._commitEmail(e)}setEmailRecipientType(e,t,i){this.cards[e].emailRules[t].recipientType=i,this.renderEmailDrawer(e),this._commitEmail(e)}setEmailField(e,t,i){this.cards[e].emailRules[t].field=i,this._commitEmail(e)}setEmailRole(e,t,i){this.cards[e].emailRules[t].role=i,this._commitEmail(e)}_commitEmail(e){let t=this.cards[e],i=this._emailConfigured(t);t.emailCode=i?oe(this.getFields(),t.emailRules):"";let n=t.emailCode&&t.emailCode.trim()!==""||t.emailRules&&t.emailRules.length>0;this.updateButtonVisuals(e,"emailCode",n),this.notifyChange()}handleLabelInput(e,t){let i=this.cards[e];i.label=t.target.value,i.key=i.label.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g,(n,r)=>r.toUpperCase()).replace(/[^a-zA-Z0-9]/g,""),this.notifyChange()}handleTypeChange(e,t){let i=this.cards[e];i.type=t.target.value,(this.registry.get(i.type)||{}).multiple?i.multiple=!0:delete i.multiple;let n=this.featuresFor(i.type),r=this.openTabs[e],a=r&&Object.entries(Oe).some(([l,s])=>s.tab===r&&n.includes(l));if(r&&!a){delete this.openTabs[e];let l=this.firstSupportedTab(i);l&&(this.openTabs[e]=l)}this.renderGrids(),this.notifyChange()}handleDefaultInput(e,t){this.cards[e].default=t.target.value,this.notifyChange()}adjustWidth(e,t,i){i&&i.stopPropagation();let n=this.cards[e];n.width=Math.max(1,Math.min(12,n.width+t));let r=this.$(`${this.uid}-width-${e}`);r&&(r.textContent=n.width);let l=this.cards.filter(h=>h.row===n.row).reduce((h,v)=>h+v.width,0),s=this.$(`${this.uid}-grid-${n.row}`);s&&s.style.setProperty("--grid-template",l>0?`repeat(${l}, 1fr) 36px`:"36px");let b=this.$(`${this.uid}-card-${e}`);b&&b.style.setProperty("--card-width",n.width),this.notifyChange()}copyCard(e,t){t&&t.stopPropagation();let i=this.cards[e],n=JSON.parse(JSON.stringify(i)),r=(i.key||"field").replace(/_copy\d*$/,""),a=`${r}_copy`,l=1;for(;this.cards.some(s=>s.key===a);)a=`${r}_copy${l++}`;n.key=a,n.label=`${i.label} (Copy)`,this.cards.splice(e+1,0,n),this.renderGrids(),this.selectCard(e+1),this.notifyChange()}requestDeleteCard(e,t){t&&t.stopPropagation(),this.activeIndex=e,this.deleteConfirmIdx=e,this.renderGrids()}confirmDeleteCard(e,t){t&&t.stopPropagation(),this.cards.splice(e,1),this.deleteConfirmIdx=null,this.activeIndex===e?this.deselectCard():(this.activeIndex>e&&this.activeIndex--,this.renderGrids()),this.notifyChange()}cancelDeleteCard(e){e&&e.stopPropagation(),this.deleteConfirmIdx=null,this.renderGrids()}addNewRow(e){e&&e.stopPropagation(),this.rowIds.push(this.nextRowId++),this.renderGrids(),this.notifyChange()}addNewCard(e,t){t&&t.stopPropagation();let i=this.registry.keys().next().value,n=this.registry.get(i),r=this._normalizeCard({key:`newField_${this.nextFieldId++}`,label:`New Field ${this.nextFieldId-1}`,type:i,width:n.defaultWidth,default:""},e),a=-1;for(let s=this.cards.length-1;s>=0;s--)if(this.cards[s].row===e){a=s+1;break}a===-1&&(a=this.cards.length),this.cards.splice(a,0,r),this.renderGrids();let l=this.cards.indexOf(r);this.selectCard(l),setTimeout(()=>{let s=this.$(`${this.uid}-label-${l}`);s&&(s.focus(),s.select())},50),this.notifyChange()}handleCardDragStart(e,t){e.stopPropagation(),this._draggedCardIdx=t,e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/plain",String(t));let i=this.$(`${this.uid}-card-${t}`);setTimeout(()=>{i&&i.classList.add("dragging")},0)}handleCardDragOver(e,t){e.preventDefault(),e.dataTransfer.dropEffect="move";let i=this.$(`${this.uid}-card-${t}`);i&&t!==this._draggedCardIdx&&i.classList.add("drag-over")}handleCardDragLeave(e,t){let i=this.$(`${this.uid}-card-${t}`);i&&i.classList.remove("drag-over")}handleCardDrop(e,t){e.preventDefault(),e.stopPropagation();let i=this._draggedCardIdx;if(i==null||i===t)return;let n=this.cards[i],r=this.cards[t];n.row=r.row,this.cards.splice(i,1);let a=this.cards.indexOf(r),s=this.$(`${this.uid}-card-${t}`).getBoundingClientRect(),b=e.clientX-s.left>s.width/2;this.cards.splice(b?a+1:a,0,n),this.activeIndex=null,this._lastAnimatedIndex=null,this.selectCard(this.cards.indexOf(n)),this.notifyChange()}handleCardDragEnd(){this._draggedCardIdx=null,this.shadowRoot.querySelectorAll(".showcase-card").forEach(e=>e.classList.remove("dragging","drag-over"))}handleGridDragOver(e){e.preventDefault(),e.dataTransfer.dropEffect="move"}handleGridDrop(e,t){e.preventDefault();let i=this._draggedCardIdx;if(i==null)return;let n=this.cards[i];n.row=t,this.cards.splice(i,1);let r=-1;for(let a=this.cards.length-1;a>=0;a--)if(this.cards[a].row===t){r=a+1;break}if(r===-1){let a=this.rowIds.indexOf(t),l=!1;for(let s=a-1;s>=0&&!l;s--)for(let b=this.cards.length-1;b>=0;b--)if(this.cards[b].row===this.rowIds[s]){r=b+1,l=!0;break}l||(r=0)}this.cards.splice(r,0,n),this.activeIndex=null,this._lastAnimatedIndex=null,this.selectCard(this.cards.indexOf(n)),this.notifyChange()}handleRowDragStart(e,t){this._draggedRowId=t,e.dataTransfer.effectAllowed="move",e.dataTransfer.setData("text/row-id",String(t));let i=this.$(`${this.uid}-row-${t}`);setTimeout(()=>{i&&i.classList.add("row-dragging")},0)}handleRowDragOver(e,t){e.preventDefault(),e.dataTransfer.dropEffect="move";let i=this.$(`${this.uid}-row-${t}`);i&&t!==this._draggedRowId&&i.classList.add("row-drag-over")}handleRowDragLeave(e,t){let i=this.$(`${this.uid}-row-${t}`);i&&i.classList.remove("row-drag-over")}handleRowDrop(e,t){e.preventDefault(),e.stopPropagation();let i=this._draggedRowId;if(i==null||i===t)return;let n=this.rowIds.indexOf(i),r=this.rowIds.indexOf(t);this.rowIds.splice(n,1),this.rowIds.splice(r,0,i),this.renderGrids(),this.notifyChange()}handleRowDragEnd(){this._draggedRowId=null,this.rowIds.forEach(e=>{let t=this.$(`${this.uid}-row-${e}`);t&&t.classList.remove("row-dragging","row-drag-over")})}updateButtonVisuals(e,t,i){let n=jt[t];if(!n)return;let r=this.$(`${this.uid}-${n.btn}-${e}`);r&&(i?r.classList.add("active",n.cls):r.classList.remove("active",n.cls))}};typeof customElements<"u"&&!customElements.get("dialog-builder")&&customElements.define("dialog-builder",K);var Ti=K;export{X as DEFAULT_FIELD_TYPES,K as DialogBuilder,D as FEATURES,ve as ICON_PATHS,G as aggregateChart,Q as buildFieldTypeRegistry,je as codegen,_e as createChartView,Re as createPreviewView,De as createStore,ye as createTableView,ke as createWorkflowView,Ti as default,$e as defaultChartSettings,S as icon,Ae as importExcelToConfig,j as normalizeChartSettings,at as typeSupports};