@paymanai/payman-ask-sdk 1.2.17 → 1.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var paymanTypescriptAskSdk = require('@paymanai/payman-typescript-ask-sdk');
4
+ var framerMotion = require('framer-motion');
4
5
  var react = require('react');
5
6
  var clsx = require('clsx');
6
7
  var tailwindMerge = require('tailwind-merge');
7
- var framerMotion = require('framer-motion');
8
8
  var lucideReact = require('lucide-react');
9
9
  var jsxRuntime = require('react/jsx-runtime');
10
10
  var ReactMarkdown = require('react-markdown');
@@ -74,20 +74,25 @@ function ChatInput({
74
74
  enableVoice = false,
75
75
  onVoicePress,
76
76
  voiceAvailable = false,
77
- isRecording = false
77
+ isRecording = false,
78
+ transcribedText = "",
79
+ onCancelRecording,
80
+ onConfirmRecording,
81
+ showResetSession = false,
82
+ onResetSession
78
83
  }) {
79
84
  const textareaRef = react.useRef(null);
80
85
  const containerRef = react.useRef(null);
81
86
  const prevWaitingRef = react.useRef(isWaitingForResponse);
87
+ const [recordingSeconds, setRecordingSeconds] = react.useState(0);
88
+ const recordingTimerRef = react.useRef(null);
89
+ const [isFocused, setIsFocused] = react.useState(false);
82
90
  react.useEffect(() => {
83
91
  if (textareaRef.current) {
84
92
  textareaRef.current.style.height = "auto";
85
93
  const scrollHeight = textareaRef.current.scrollHeight;
86
94
  const maxHeight = 160;
87
- textareaRef.current.style.height = `${Math.min(
88
- scrollHeight,
89
- maxHeight
90
- )}px`;
95
+ textareaRef.current.style.height = `${Math.min(scrollHeight, maxHeight)}px`;
91
96
  }
92
97
  }, [value]);
93
98
  react.useEffect(() => {
@@ -105,6 +110,25 @@ function ChatInput({
105
110
  });
106
111
  }
107
112
  }, [isWaitingForResponse]);
113
+ react.useEffect(() => {
114
+ if (isRecording) {
115
+ setRecordingSeconds(0);
116
+ recordingTimerRef.current = setInterval(() => {
117
+ setRecordingSeconds((s) => s + 1);
118
+ }, 1e3);
119
+ } else {
120
+ if (recordingTimerRef.current) {
121
+ clearInterval(recordingTimerRef.current);
122
+ recordingTimerRef.current = null;
123
+ }
124
+ setRecordingSeconds(0);
125
+ }
126
+ return () => {
127
+ if (recordingTimerRef.current) {
128
+ clearInterval(recordingTimerRef.current);
129
+ }
130
+ };
131
+ }, [isRecording]);
108
132
  const handleKeyDown = (e) => {
109
133
  if (e.key === "Enter" && !e.shiftKey) {
110
134
  e.preventDefault();
@@ -120,101 +144,178 @@ function ChatInput({
120
144
  if (!isSessionParamsConfigured) return "Configure session params to begin";
121
145
  return placeholder;
122
146
  };
147
+ const formatTime = react.useCallback((seconds) => {
148
+ const mins = Math.floor(seconds / 60);
149
+ const secs = seconds % 60;
150
+ return `${String(mins).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
151
+ }, []);
152
+ const handleCancel = () => {
153
+ if (onCancelRecording) {
154
+ onCancelRecording();
155
+ } else if (onVoicePress) {
156
+ onVoicePress();
157
+ }
158
+ };
159
+ const handleConfirm = () => {
160
+ if (onConfirmRecording) {
161
+ onConfirmRecording();
162
+ } else if (onVoicePress) {
163
+ onVoicePress();
164
+ }
165
+ };
123
166
  return /* @__PURE__ */ jsxRuntime.jsx(
124
167
  "div",
125
168
  {
126
169
  ref: containerRef,
127
- className: cn("flex-shrink-0 w-full", className),
128
- style: { flexShrink: 0 },
129
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-3 pt-1.5 w-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full max-w-2xl mx-auto", children: [
130
- /* @__PURE__ */ jsxRuntime.jsxs(
131
- framerMotion.motion.div,
132
- {
133
- initial: false,
134
- className: cn(
135
- "flex items-end overflow-hidden",
136
- "payman-chat-input"
137
- ),
138
- children: [
139
- /* @__PURE__ */ jsxRuntime.jsx(
140
- "textarea",
141
- {
142
- ref: textareaRef,
143
- value,
144
- onChange: (e) => onChange(e.target.value),
145
- onKeyDown: handleKeyDown,
146
- onClick,
147
- disabled: isInputDisabled,
148
- placeholder: getPlaceholder(),
149
- className: cn(
150
- "payman-chat-input-field",
151
- "focus:outline-none resize-none overflow-y-auto",
152
- "flex-1 min-w-0 py-3"
153
- ),
154
- style: {
155
- minHeight: "44px",
156
- maxHeight: "160px",
157
- paddingLeft: "18px",
158
- paddingRight: "8px"
159
- },
160
- rows: 1
161
- }
162
- ),
163
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 shrink-0 p-2", children: [
164
- showVoiceButton && /* @__PURE__ */ jsxRuntime.jsxs(
165
- "button",
170
+ className: cn("payman-chat-input-wrapper", className),
171
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-chat-input-container", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-chat-input-inner", children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: isRecording ? (
173
+ /* ======== Recording State ======== */
174
+ /* @__PURE__ */ jsxRuntime.jsxs(
175
+ framerMotion.motion.div,
176
+ {
177
+ initial: { opacity: 0, y: 6 },
178
+ animate: { opacity: 1, y: 0 },
179
+ exit: { opacity: 0, y: 6 },
180
+ transition: { duration: 0.25, ease: [0.25, 0.46, 0.45, 0.94] },
181
+ className: "payman-chat-input payman-chat-input--recording",
182
+ children: [
183
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-recording-transcript-area", children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: transcribedText ? /* @__PURE__ */ jsxRuntime.jsxs(
184
+ framerMotion.motion.p,
166
185
  {
167
- type: "button",
168
- onClick: onVoicePress,
169
- disabled: isVoiceButtonDisabled,
170
- className: cn(
171
- "relative flex items-center justify-center",
172
- "w-8 h-8 rounded-full transition-all duration-200",
173
- "payman-chat-input-btn-voice",
174
- isRecording && "recording"
175
- ),
176
- "aria-label": isRecording ? "Stop recording" : "Voice input",
186
+ initial: { opacity: 0 },
187
+ animate: { opacity: 1 },
188
+ exit: { opacity: 0 },
189
+ transition: { duration: 0.15 },
190
+ className: "payman-recording-transcript-text",
177
191
  children: [
178
- isRecording && /* @__PURE__ */ jsxRuntime.jsx(
179
- "span",
192
+ transcribedText,
193
+ /* @__PURE__ */ jsxRuntime.jsx(
194
+ framerMotion.motion.span,
180
195
  {
181
- className: "absolute inset-0 rounded-full border-2 animate-ping opacity-40",
182
- style: {
183
- borderColor: "var(--payman-input-btn-voice-recording-ring)"
184
- }
196
+ className: "payman-recording-cursor",
197
+ animate: { opacity: [1, 0] },
198
+ transition: { duration: 0.8, repeat: Infinity, repeatType: "reverse" }
185
199
  }
186
- ),
187
- isRecording ? /* @__PURE__ */ jsxRuntime.jsx(
188
- lucideReact.Square,
189
- {
190
- className: "w-3 h-3 relative z-10",
191
- fill: "currentColor"
192
- }
193
- ) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "w-4 h-4" })
200
+ )
194
201
  ]
195
- }
196
- ),
202
+ },
203
+ "text"
204
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
205
+ framerMotion.motion.p,
206
+ {
207
+ initial: { opacity: 0 },
208
+ animate: { opacity: 0.5 },
209
+ className: "payman-recording-transcript-placeholder",
210
+ children: "Listening..."
211
+ },
212
+ "placeholder"
213
+ ) }) }),
214
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-recording-bar", children: [
215
+ /* @__PURE__ */ jsxRuntime.jsx(
216
+ "button",
217
+ {
218
+ type: "button",
219
+ onClick: handleCancel,
220
+ className: "payman-recording-btn-cancel",
221
+ "aria-label": "Cancel recording",
222
+ children: "Cancel"
223
+ }
224
+ ),
225
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-recording-indicator", children: [
226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-recording-dot" }),
227
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-recording-timer", children: formatTime(recordingSeconds) })
228
+ ] }),
229
+ /* @__PURE__ */ jsxRuntime.jsx(
230
+ "button",
231
+ {
232
+ type: "button",
233
+ onClick: handleConfirm,
234
+ className: "payman-recording-btn-confirm",
235
+ "aria-label": "Confirm recording",
236
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4", strokeWidth: 2.5 })
237
+ }
238
+ )
239
+ ] })
240
+ ]
241
+ },
242
+ "recording"
243
+ )
244
+ ) : (
245
+ /* ======== Normal Input State ======== */
246
+ /* @__PURE__ */ jsxRuntime.jsxs(
247
+ framerMotion.motion.div,
248
+ {
249
+ initial: false,
250
+ animate: { opacity: 1, y: 0 },
251
+ exit: { opacity: 0, y: 6 },
252
+ transition: { duration: 0.2 },
253
+ className: cn(
254
+ "payman-chat-input",
255
+ isFocused && "payman-chat-input--focused"
256
+ ),
257
+ children: [
197
258
  /* @__PURE__ */ jsxRuntime.jsx(
198
- "button",
259
+ "textarea",
199
260
  {
200
- type: "button",
201
- onClick: onSend,
202
- disabled: !canSend,
203
- className: cn(
204
- "flex items-center justify-center",
205
- "w-8 h-8 rounded-full",
206
- "payman-chat-input-btn-send",
207
- "hover:opacity-90 active:scale-95",
208
- "transition-all duration-150"
209
- ),
210
- "aria-label": "Send message",
211
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-4 h-4", strokeWidth: 2.5 })
261
+ ref: textareaRef,
262
+ value,
263
+ onChange: (e) => onChange(e.target.value),
264
+ onKeyDown: handleKeyDown,
265
+ onFocus: () => setIsFocused(true),
266
+ onBlur: () => setIsFocused(false),
267
+ onClick,
268
+ disabled: isInputDisabled,
269
+ placeholder: getPlaceholder(),
270
+ className: "payman-chat-input-field",
271
+ rows: 1
212
272
  }
213
- )
214
- ] })
215
- ]
216
- }
217
- ),
273
+ ),
274
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-chat-input-bottom", children: [
275
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-chat-input-actions-left", children: showResetSession && onResetSession && /* @__PURE__ */ jsxRuntime.jsxs(
276
+ "button",
277
+ {
278
+ type: "button",
279
+ onClick: onResetSession,
280
+ disabled: isWaitingForResponse,
281
+ className: "payman-chat-input-btn-reset",
282
+ "aria-label": "New Session",
283
+ children: [
284
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { className: "w-3.5 h-3.5", strokeWidth: 2.5 }),
285
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-chat-input-btn-reset-tooltip", children: "New Session" })
286
+ ]
287
+ }
288
+ ) }),
289
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-chat-input-actions", children: [
290
+ showVoiceButton && /* @__PURE__ */ jsxRuntime.jsx(
291
+ "button",
292
+ {
293
+ type: "button",
294
+ onClick: onVoicePress,
295
+ disabled: isVoiceButtonDisabled,
296
+ className: "payman-chat-input-btn-voice",
297
+ "aria-label": "Voice input",
298
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mic, { className: "w-[18px] h-[18px]" })
299
+ }
300
+ ),
301
+ /* @__PURE__ */ jsxRuntime.jsx(
302
+ "button",
303
+ {
304
+ type: "button",
305
+ onClick: onSend,
306
+ disabled: !canSend,
307
+ className: "payman-chat-input-btn-send",
308
+ "aria-label": "Send message",
309
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "w-4 h-4", strokeWidth: 2.5 })
310
+ }
311
+ )
312
+ ] })
313
+ ] })
314
+ ]
315
+ },
316
+ "input"
317
+ )
318
+ ) }),
218
319
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-chat-input-disclaimer", children: AI_DISCLAIMER_TEXT })
219
320
  ] }) })
220
321
  }
@@ -783,6 +884,7 @@ function MessageList({
783
884
  isLoading = false,
784
885
  emptyStateText = "What can I help with?",
785
886
  showEmptyStateIcon = true,
887
+ emptyStateComponent,
786
888
  layout = "full-width",
787
889
  showTimestamps = false,
788
890
  stage = "DEV",
@@ -907,7 +1009,7 @@ function MessageList({
907
1009
  }
908
1010
  if (messages.length === 0) {
909
1011
  const lines = emptyStateText.split("\n").map((l) => l.trim()).filter(Boolean);
910
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("payman-empty-root p-8", className), children: /* @__PURE__ */ jsxRuntime.jsxs(
1012
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("payman-empty-root", className), children: /* @__PURE__ */ jsxRuntime.jsxs(
911
1013
  framerMotion.motion.div,
912
1014
  {
913
1015
  initial: { opacity: 0, y: 20 },
@@ -915,17 +1017,17 @@ function MessageList({
915
1017
  transition: { duration: 0.5, ease: [0.25, 0.46, 0.45, 0.94] },
916
1018
  className: "payman-empty-content",
917
1019
  children: [
918
- showEmptyStateIcon && /* @__PURE__ */ jsxRuntime.jsx(
1020
+ emptyStateComponent && /* @__PURE__ */ jsxRuntime.jsx(
919
1021
  framerMotion.motion.div,
920
1022
  {
921
- initial: { scale: 0.85, opacity: 0 },
1023
+ initial: { scale: 0.9, opacity: 0 },
922
1024
  animate: { scale: 1, opacity: 1 },
923
- transition: { delay: 0.08, duration: 0.45, ease: [0.25, 0.46, 0.45, 0.94] },
924
- className: "payman-empty-icon-wrap",
925
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircle, { className: "h-7 w-7 payman-empty-icon", strokeWidth: 1.5 })
1025
+ transition: { delay: 0.05, duration: 0.45, ease: [0.25, 0.46, 0.45, 0.94] },
1026
+ className: "payman-empty-custom-component",
1027
+ children: emptyStateComponent
926
1028
  }
927
1029
  ),
928
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1.5", children: lines.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx(
1030
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-empty-text-group", children: lines.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx(
929
1031
  framerMotion.motion.p,
930
1032
  {
931
1033
  initial: { opacity: 0, y: 6 },
@@ -1003,18 +1105,26 @@ function MessageList({
1003
1105
  }
1004
1106
  ) });
1005
1107
  }
1108
+
1109
+ // src/assets/payman-mono-crop-blue.png
1110
+ var payman_mono_crop_blue_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAMMCAYAAADDyBY0AAAACXBIWXMAAG66AABuugHW3rEXAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAGA7SURBVHgB7d07kFt3luf5cy4eophUDOTVbFWJINXRUc6Mkp7EpEJgKFOhsZT0ui0mvVmLpLW9FpPW7Fgkre2xmPS6LKYidqfVYmoItki2xmKWVxNRTUFSGesV1MqkqARw//v/45FPPC6Ae4H7+H6i1UyRrCoVKwH87jn/c/4qAJAgpUql3NgrlOyXi76akud5Z8Vv2b/XsrF/dX6XKUv61FW0Zv+71Y2xX+e8mu/73+U9r2aMX8/nm7V6tVoTAAhABQBipFRZLTX2dsv2y0XjmbIac/Yg3KUy2IVMayqm5kKiePIH9e3fe6ZGQARwGAEQwMz1D3neoukEvJIgMraKuG2MqblwmFNvu1M9PLNdr27WBUBmEAABRKrbsq24oCe+vCeqi1TyYsm2mGVbPG/btZZzKtsEQyC9CIAAQrNwccWGO1mUnL4nvqlQ0Uu+XsXQqDwhFALpQQAEMJFeZY+wl0VaE2O2CYVAchEAAYzkzuw1mzuLLSOLauQj+85REcIeDnGVQnEtZCNP3I+7zx9tC4DYIgACOMEFvlbrVcUXG/Z8f9FIO/AB46jbMFjtVQl3nm5VBUBsEAAB7Ff4jHqfddu5iwKEqz1kYh8qPicQAvNHAAQy6syl5Yrvy0dq27lU+DAH+xVCz2iVljEwWwRAICNcle+Xxs4aZ/gQT26BtVQ9Tz/P5U5XGSoBokUABFKMKh+SyoVB1y6mOghEgwAIpMjhs3zG99eEKh9SoVMdVDUPODsIhIMACCRc91q1VSPmM1q7yIC6im7SKgamQwAEEqgX+kTNVeNu3iD0IauMbNpA+HmhuLBJGASCIwACCUHoA0YgDAKBEQCBmHODHMa40KerQugDArFBcMO1iX/6+stNAXACARCIoXboY5ADCAEDJEA/BEAgJlyLd29v5zorW4CoaE2M2SgW8w/q1S9qAmQYARCYs06LV24R+oDZcVVBMfpg9/mjDQEyiAAIzEGv2mdfgTeEFi8wR50WsRi5x8JpZAkBEJghqn1AfKnodjcIbgiQcgRAIGJU+4Ck6VQFC4Xcbc4KIq0IgEBE2vfwGr0qYljfAiQUZwWRVgRAIGS0eYE0slVBI7cLxVyVqiDSgAAIhIA2L5Adbsk07WEkHQEQmALBD8guFwRZMI2kIgACEzh0vm9NAGQa5wSRRARAYAyc7wMwWOecIEEQSUAABAIg+AEIjiCI+CMAAkMQ/ABMjiCI+CIAAn0Q/ACEhyCI+CEAAocQ/ABEhyCI+CAAAkLwAzBLBEHMHwEQmbZwcWVR1Nwh+AGYPYIg5ocAiEw69f6nZS/XusUePwDzRxDE7BEAkSnc3AEgvnTbU3OTm0UwCwRAZMbpi8u3CH4A4o67hjELBECkXvfatvu23VsWAEgIgiCiRABEajHZCyD5tGZ8c+/nf9m6K0CICIBIHXfOr9HYccHvhgBAKjAognARAJEqb36wcl09sy6c8wOQQrSFERYCIFKh0+7VO0bMogBA2hlZf/V867YAEyIAItFo9wLILtrCmBwBEIlFuxcAaAtjMgRAJA7XtwFAH7SFMQYCIBLj0C0e6wIA6ENrxULuMtVAjEIARCKwzBkAglPx7hYKp21beLMuQB85AWLMVf1yv/7Nf7Ht3r8XzvoBQEDm/Zbf+Jvib9/9sfHDy20BjqECiNii6gcA02NIBP1QAUTsuKqf9+vf/t+26ueuPqLqBwDTWWz5ZpVqIA6jAohYoeoHANGhGogeAiBigYXOADArWst5evOnr7/cFGQWARBzR9UPAGaPSeFsIwBibqj6AcC8sTcwqxgCwVy42zxafuOx/fJTAQDMS6nl+zcKvz0vjR9ePhFkBhVAzBx3+AJA/KjodqGQu0I1MBsIgJiZU+9/Ws7lmve5wxcA4kprauT27vNHG4JUowWMmXCDHqLmof1yUQAAcVWypaHV4jt/VVp49z/8z9e1P74WpBIVQERuYWn5DoMeAJA0DIikGRVARMa1fN84W35ow9/fCAAgadyAyFr+N+d/af755TeCVCEAIhJvffjJqmjrH+2XvxMAQFKdUpVPaQmnDy1ghI6WLwCkES3hNCEAIjRM+QJA6tXV6E2mhJOPAIhQcJ0bYq5u3+7qqqZuH1Bqakxd1PvRiKmrrzX3G7ycXzdG21di5fPN2sG/tFSf9KqsUqVS7n3dbOb3vza+tr82Xuf1Yv95zhrVkn1DLtl/Bvtzxu3IZE8m4svI+qvnW7cFiUUAxNROX1y+Zb+T1gWYj3a4sylq2wU7X/QPng1y6plaJ8hNHuDmzQVIFxxtcC01bWj0VMs2tJ7tBMX2SiVCIubGfh9WC4X8NVrCyUQAxMTcXb57ezv33c4oAaJlq3dSE2O2baXsu27VbrtQXKhl+SL79n3ae7tlW70s9wKiLc28RzjE7HAuMKkIgJiIO+/n5VqPafkibDbobbug5yp5eVvFy+Va2/VqtSYYiwuHzebOYsuGQYIhIlY3vtz++V+27goSgwCIsS0sfXzViLoXOh8kmEa9HfZs0BPf/Sjbu88fbQsidTgY2j//j+yHQLkbDIHpcC4wUQiAGAvn/TA5ran41e4ZvSphLz56odAXqdgPhY+oFGJiRjaLxTPXsnw0IykIgAikfdaosfOQFS8IylaXqq6656lfzeXeqvKBkCwLF1dcCFw0akOh7rePgQA4F5gEBECMxHk/BNELfCpmM58/s03gSxf3PlAoNBZbvueGvj7i/QDD2Yq/kStU+uOLAIihOvv95KHQDsIJ9g1e5XMqfNnUXvzutSrGM5+J0UUCIfqo2wfCG7vPvnogiB0CIAZ684OV6+oZprrQ0x7asA8En79RaG4ymYvD2g+LB2cIKwL0MBwSSwRA9MV9vuhyT/CbniefU+VDUEerg+0wSAch6wiBsUMAxBEMe0DalT594ILfztOtqgBTeuvDj1c5OwgmhOOFAIh9DHtkGqEPM9G9N3xNCIMZxYRwXBAA0eZWPhh1wx68IWcIoQ9zRRjMKkJgHBAAwc0e2dIe5LAv/NusakGcHLSJzVVBBhAC540AmHHc7JENbkdfZ3r3zAahD3HWGyARz1xlmjj16mr0MrsC54MAmGFM+qYeLV4kWvdc8rrQIk41+x61xq7A2SMAZpCb9N1r7N6xb6hrgtSh2oc0Wri4skZVML2MLzd//pct9s7OEAEwYzprXnYfGzHc65kuVPuQCVQFU4xdgTNFAMwQ1rykUt2+iu8V82fuUu1D1riqoFG5xXtaihACZ4YAmBGEv3RxbV43yUu1Dzi8ToYJ4lQgBM4EATADOjv+jA1/rHlJPJVNT+QewQ846aA9TBBMPEJg5AiAKdd5MnYLngl/CdZt8+Y32JkFjNYOgvnmmhi9StcjwQiBkSIAplh3wfOGIKk43wdMiXOCCUcIjAwBMKXe/GDlunqGkfpkIvgBISMIJpfaQsbus0fXBKEiAKYQt3skFsEPiBhBMJkIgeEjAKYM4S+RCH7AjBEEE4h2cKgIgClC+Escgh8wZwTBhCEEhoYAmBKEv2RR1XuF/MI6wQ+IB4JgghACQ5ETJB7hLzncAudiIX/5p3/+8h9e1/74WgDEQuOHl9u5X//155rzf7R/WxHEl0ql8Nvz7n+zJ4KJUQFMuNNLK/ft49CaINa4uQNIDhZKJwSVwKkQABOM8JcEWst5evOnr7/cFACJ0l0ofccGjVVBPBECJ0YLOKEIf7HnBjz+a7Fw5tq//fP/uy0AEqf55z/VG9+//H3xt+9+Z8v4i8KNSvFj28HFd87VGj98+wfBWKgAJhDhL+aMbBaL+Ztc2waky+lLy+v29X1dCIKxo/YzcffZVw8EgREAE4bwF18quq1qbnLOD0gvzgfGVl2NXt59/oiOS0AEwAQh/MVW3Yjc/vnZFlfvARnx1ocfr7Z87w5rY2KFEDgGAmBCsOolntx0byGfv0a7F8imblv4liAmtFYs5C7znjwaATABCH9xpDVPzTXavQBcWziXa9437A+MCUJgEATAmCP8xQ+3eADoh9tE4sOdyS4UFi7zPj0Ya2BijPAXN67qJ1d2n279Pbd4ADhu/zYRz7xt/3ZRME+/8v3Gr+z/Jp8L+iIAxhThL15c1a9YWPjbf/vn//5HAYAB2rsDf3i5ye7AWFgsvvNXpcYP//pPghMIgDFE+IsTqn4Axkc1MC7M+9wb3B8BMGYWlj6+ap8aWScSA1T9AEyDamBMcFtIXwyBxMiZS8sV38hjwZwx4QsgXEwKzx07Ao8hAMbEwsWVRaPGhT+eEOepfY3bmWtMjgGIAnsD54n1MIcRAGOge7XQY1YHzBW3eQCYCd7z54f1MAc4AzhnvBHMn3tDKBbyl3e+/vILAYCIubOBC+++88A3+qZ9B3pfMEush+kiAM4R4W/+3KDH7rNHV17X/kTLF8DMvK7VXje+//aLzoBI+1zgKcGsLDIZLOIJ5iaXaz0k/M1N3VO5vPv00Q0BgDnZff5ow2/lL7jzaYLZUVlvb93IMM4AzsnppZX7NvytCWZOVaqFfP4aB4EBxMnCpY/vGqPXBbNSLxbyF7L6WUAAnAMWPc9Pu+VL1Q9ATC0sLd8w0p4SZiPETLjJ4IULWRwKoQU8Y4S/uannPO8K4Q9AnO0+27pLS3iWTLnR2HkoGcQQyAxxy8d89KZ8/+2f/+kbAYCY600Jt1re7+wb2O8EUStncSiEADgjnUXP8g/CpNdMuZZvobBwrV79f/4/AYCEaE8J//Dy94Wz591RrYogWiqVU+W/+sPe9/+amas/OQM4A6x7mQ8jcpPFzgCS7q0PP15t+XpfOBcYtUwNhRAAI1aqrJb2GrsvCH+zpDU1coU7HwGkBYWE2cjSTSEMgURsb2/nPi/Y2emc98tx4TeAVHn9zRc1v5W7bKs2vLdFyIhZbDReZeKuZs4ARqg78fufBTPBeT8AaeaGQxo/vPxvxbPn3uYKuSiZ9/O/Of9j888vUz04SAs4Im9+sHJdPcP5s1lRuf3q6da6AEAGnL60vG7LVZmoVM1J6s8DEgAj0Jn4NS8Es+D2+1376esvNwUAMqS7NPqOICLpXhLNGcCQuYO6RiWTSyVnz7048xcIfwCyyC2NVqMX7JeZu8ViNtyS6PSeB6QCGCImfmenM6mVu8J9vgCyjgnhaKmYtd1nXz2QlKECGCIb/u7wApwFfdAZ0yf8AUBvQpjr46JhRO+WKp+WJWUIgCFpT/zapwRBtNywx7NHa1m8uBsABmFNTKRKjUbzvqQMa2BC8NaHn6waMX8viFT3Zo//SwAAJ3TvEP6973uf2r/9lSBM5bSthuEM4JQ4ezETTPoCwBhOL61s2M+lq4JQuaGbtFw0QAVwCm7owze//AvhL0ruWjf9TzvPHlUFABBI44eXmyyMDp+qvr/w7n/8/evaH19LwhEAp5D79W/+i/3hU0FE3JqX3GVb+fujAADG0vj+2y8KZ8+7Tl9FEJZf+X7zVOOHf/0nSTgC4IS617z9nSAinfDHpC8ATK7x/csqITBs5v03zp5/svf9y5okGAFwAu6mDxv+/kEQCbfjr1hY+IA7fQFgeoTA8BnRim0FP0hyK5gAOCY39KGe+Uf7ZUkQAX1gw9/fsuYFAMJDCAxdKemtYALgmIrvlO/bEhWHaiOhD9yOvzQcrgWAuCEEhi3ZrWAC4Bi65/7+syB87QXPWzcEABAZQmC4ktwKJgAGxLm/CLnw93RrXQAAkSMEhiqxrWACYACc+4sQ4Q8AZo4QGKZktoK5CzgAz2veYdlzBAh/ADA3nfdffSCYmjF6RxKGCuAInPuLCOEPAObO3RhSeOfdc/bLRcE0fpW0u4K5C3iIzj2/zW8F4SL8AUCsLCwtvzCEwGnVi4X8haRcYEALeAB3z6+Xaz0WhIvwBwCxUyg0L9uK0LZgGqVGo3lfEoIAOECjsXOLc38hI/wBQCzVq9V6q5W/4q7hFEzMVlErZy4tVyQBaAH3sXBxZc2oSUyKTwTCHwDEXufok+t+UQCZnLvLfuFC3G+0ogJ4jPvmNyq3BOEh/AFAIrz+5ouaGrGVQOE6zomZ8l5zJ/YXGxAAj8nlXP+eJ5/QEP4AIFF2nz/a9rQdAjEpI9dLlU/LEmMEwEPcyhfDUszwEP4AIJF2nm5VVeSmYFKxHwhhD2BX57YPf1MQDsIfACRa44eX33BbyFTKcb4hhApgFytfwqOq9wh/AJB83BYynTjfEEIAlO5tH5z7C4k+2H36KPaHXwEAwRQLjRvsCJyMEbP45gfLsfxMzPwaGG77CI+qVHefbl0WAECqsB5mKvVi4cy5uK2FyXwFkNZvOFR0u5A/w9QYAKQQ62GmUorjWphMB0Bav2HRWqGQuxL3pZcAgMm59TBqlMngScRwLUxmp4CZ+g2L23ieu5yUy68BAJNr/PBym8ngiZzyfVOyf36fS0xktgJI6zcUdcIfAGSLmwy2CbAqGIsRs7ZwcWVRYiKTAZDWbzhsK4DwBwAZVCg0r7gOkGA8amKzFiZzU8BM/YbDiNz8+dnWXQEAZFL38/SF/bIkCMxTuexuWpE5y1wFkNZvCFRuE/4AINs6k8EMhYzLGLklMZCpIZB261dlVTCx7i0ffycAgMxzQyHFs+fetp8O7wuCisUVcZmpALpStQ1/64KJdRY9c8sHAOBAId9a56aQ8cShCpiZAJjLNe8LpqA1Fj0DAI6rV6v1VivPkugxGJHKmUvLFZmjTAyBLFxcWTNqCIATY9cfELVSZbVkPz/3D9M39gol9cyJw/X5fLN26F9VZwE74oLP2vG4VTq7z+Z3fWrqAyD3F05PjV5wG+AFQGC9QNdqFRf9likZz5TVmLOdX9WysX91vg7rvUlr2q7AmLptL9VV7Y+q36lvf94zNeNrvVBcqBEYEaWFSx/fNUavCwKZ50RwXlLOhj92/k3BrXt5RfgDBipVKmUX8pq+X/bEvGffdRaNu/uzsVPuvMX6nUdt4/7v8DO3kXCZ8v6/o3b/s9x/php33sg9yYn9Z5LTS8t1d17LhUTx5A859bZtQK3xkIcwuPOAe43CZ3zuBtM9C1iVOUh1BdD1130jrH2ZlMptt/FdALS5sGdbsxXJ6Xvi+y7oua3+qdmBpqI2GNpqocqTnMp2Pn9mm4ohxuVuu7APHu6zl/2AAcyrCpjqAHh6aeVbnkIm05n4nd/ZBGDeXAu32dyxH2TeZ2kMe0G5UChuwtPIE/cjlUIEsbC0fMO+ZmJz60WczessYGoDYHfn37pgAgx9IHv6BL6KoA+t2b7Vtg2GnxeKuSrvExjEhsDHvI6CmUcVMJUBkOtpplIvFvIXeFNHFriW7i+N/Kon8llWK3zTaw+fVFXNgzhcb4X44LM4uHlUAVMZAG3r975t/a4JxqZGr9kWz4YAKdU+G+zLR6pSoToRASObVAfRQys4OFt8OTfL10zqAuBbH3682vL1oWB8DH0gpXqhT1TXOBc8O66qIUYfEAazjVZwQDP+DE5dAGTwYzIMfSBt3Jm+vb2d61T6YqJbGaTDkD20ggOrFwtnzs1q8j4nKfLmByv2zd78jWBMbugjf+V17U+se0DiuWpf4bfn77f8vb+3j7gV+1Nlwfyp/M7+tVp45/yN4jvv/u6Ns+d/3Pv+ZU2Qes0//6lefOf8L/bLTwXDnGqZvV8a37+sygykpgLIjR+T46YPJF2v2mff0W4IVYYE0ZoauU2LOBtoBQdSf/Vs622ZAU9Sghs/JqRym/CHpHLVPvehstfY+Ut37RPhL1FM2d0du9dovlhYWrlfqnxaFqRWq5W/Ju3rCjFE6fSHn6zKDKSiAtg9X/CtYCwqurH77NE1ARLGXTpvS9dXqSakT2eljNxmpUw6nb60vC6d688wwKxWwqQiAFJWngTLnpEstHmzptMeZmgkfexn9ovu3k0MMIvF0IlvAbtKAOFvfIQ/JIULfu5mH9vm/ZY2b5Z02sNus0O74ovUsBXem4KhjGjkbeDEVwBZ+zIB9v0hAaj44SgqgmliP7s37Gf3VcEgka+ESfQamO45oDVBYG7fnw1/nPtDbLng5/1vv/k/Wv7eP9jw59ZGnBLAPQS018i8u1b87bs/Nn54yfBagi28+0615Xv/WXh9DxL5SpjEtoDd4IdRDpKOR2uFfJ7wh9hyD3V7jd0XtHoxGK3hNKhXq3X7Or8nGMzoZxKhxLaAF5aW7xhpt4YQEPf8Iq7cOhdj5BbneTEuNzFZKOSvcaY5mTjGNVyUwyCJrAC2q3+Ev7Go6j3CH+LGvZbdFL9vhEl+TMR93+w1mt+yRzCZPDV0pYbwfbkuEUnkGcDi2XN3hBHyMWjt1bNH/0mAmOid81PP37B/+zsBprfY8s0q5wOTxV0HWHznfEW4srE/lV8tvPsf/9vr2h9fS8gSVwF0FQP7zLcmCMytfBEgJly7l3N+iMbB+UCqgcnhFn8LBin90thZkwgkLgB2rnxDYPaFxdkYxEF7n59t07l2L2d+EC1T7rSFP7njvu8EsdY546YPBH3ZoBbJMEiihkBc5aDz4YFg2q3fcwLM2VsffrLa8v37QsUPM6c18fTmq6+/3BTEFle6DhfFMEiizgAWfnvefYCUBUHUi4X8B69rf+LibcyNq77kfv2bf/SN+Tth3xfmoyTG/E3xnb8qLbz7H/5nFGepML3mn/9UL5w974pSFcFJqj82vn/5hYQoMS1grnwbj/2zovWLuXJVP3d9G69bxIER/4Y7e+o6SYJYKuabd+0PFC36MCb8W1MSUwEsvPPuQ6F9FEj7to9nW/+7AHPQrfr9F1v1c2/mVP0QJyX7QLJmu0nS+OHlE0GsvK7VXtsq4JvCQ2M/p944e/6Jm5qWkCSiAtjZ9s6h8YDq3PaBebGv1UVXZWFPJ2JNZZ1J4XiiCjhY2FXARARArnwLjtYv5uXND1auGzUveFhDMrQnhV9wnVy8cEXcYEZ0Ncyp9tgHQKp/wanq9s/Ptu4KMEPuDcnd5qGe4XsPSVNyewPduhhBbFAFHKjUaO2uSkhiHwCp/gVXyOeuCDBDh1q+FQESyg2I0BKOD6qAQ/jhtYFjHQCp/o2Bhc+YMVq+SBfXEm49Zko4HqgC9mcfthfDagPHegqYyd+g3MLnLap/mInelG/3KjcgTZgSjgk3EVw8e+7f28+39wWHnfKl8b8a309/33VsK4BU/4Ljrl/MitvW32jsPmbKF6lmH244Fzh/rWaBc8X9hNQGjm0A5OxfMKp6j9YvZsGd9/NyLRv+zKIAKefOBS4srbzgXOD8vP7mi5qKVAVHhNUGjmUApPoXlNYK+RxPSIjcwtLHV42ax7wukSXuYcedCyQEzo+q3BYcV9prvarIlOJZAfTMdcFIahj8QPROX1y+ZUQ3hPO4yKTOcAghcD52nm5VqQKepH7rM5lS7AKgm8AyRmgxjaD2A3n3+aMNASK0sLR8h2EPYH9pNJ9N82D0geAItxRaphS7AGjDH2f/AigUcpTFEZnecmeGPYB9bmn0C3ccQjBThWJjU1gJc1xp2pVFsQqAbsKQhbIBsPMPETo06VsRAEe44xBvfrDMg9EMsRi6v2mrgLEKgF6uRfVvJK29erq1LkAEXPhj0hcYTj25487GCmamuxgah9iO6VTnAGMTAN0Hj/2vsyYYyg1+CBCBXvhj0hcIQGWdEDg7rgrIMMhxplyqVMoyodgEQKp/AahsMviBKHR2/DW51g0YByFwplgJc9IvjfzEbeBYBECqf8EU8/mbAoTMhb/Ojj/WvABjIwTOjFsJIwyDHGFD3MRt4FgEQM9rMlU1glv7wuAHwkb4A0JgQyCDITPCMMgR09wKEo8WsOqaYAitsfYFYSP8AeFxgyGsiIkewyAnlJrNnYmG9uYeALn2bTQjhvt+ESrCHxA+tyLmrQ8/mXpBLwZjGOSkSdfBzD0AGmXx83Ba+/nZFk88CA3hD4hOy/fvc2NItHyRzwUHjHlPJjDXANjZYk31bxjWviBMhD8gciVb2HjI3cHReaPQ3BCGQfa5pf2TnAOcawDk2rfhVHWbtS8IS/umHfvBJIQ/IGLu7uDWY0JgNNo3g4hSBTxkr/WqImOaWwDk2rcAfLkmQAhY8gzMmik3Gq2Hk05oYjhPzYZgnxpTkTHNLQCy+Hk4t/bFVv+2BZgS4Q+YD3elYqOxe0cQuny+6T4faQN32Y7qRzKmuQTAUqVin4gMk1JDsPYFYXDVB8IfMD82BK6xKDp8tIGPM2PvA5xLAGzsFVz4oyw+AEufEZa9vZ37hD9gzlTW2REYPtrAR417DnAuAZDVL8NR/UMYFpaW79gPHirtQAwY0bsMhYSLNvBR454DnHkAZPXLcFT/EAbXcjIiXE0FxEepMxnMUEhYaAMfM+Y+wJkHQN8oZfAhqP5hWm9+sHLdtZwEQMyYcudYBsKihltBety9wOP8/pkGQDeNaP8R1wT9qdym+odpuNeYemZdAMSTyuqbHyxTnQ9JodjYFPSUxrmFZqYBMOe1KoIBtFbM5zcEmNDBuhcGrIA4U0/udI5DYVrcDXyUr8HPAc40ADL8MYSaB1T/MI1crvWQ87VAMvhG73MeMBzcDXzAk+DnAGcWABn+GIbqH6bjJn7d0lkBkBCcBwyLaeVpA3cZ8SpBf+/MAiDDH0NQ/cMU3NAHE79AAnEeMBSvv3Gfn1oTiHuwCFpZnkkAZPhjGKp/mFx36OOuAEgk9eQW+wGnp+rTBu5qNncCdYNmEgAZ/hjMHV6l+odJHBr6AJBcpUajSSt4Wr63LWhrGYlPAGT4YzD2/mFSNvzd4lxtqtU7ba3jfyFtjEiFVvB0WAdzIOggiErE3PCHb4QqRR/u1o/dZ4+uCTAmd+6P1m9i1VWlJsZsG9Xv1Nea/d+yls83a+1frFZrQf5NOud86qVmM19WNaWmr2VPtWzEnLVv7GVjxlsKi7mrFwv5C3SEJrdwafkF3/eObr969ujCqN+Vl4h1hj+M4CSqf5hE59xfk/CXCDbciV/1Rf+QU9nO589s16ubodxd2v33cX/VBv0etxTWy/ll33gV+z78XvfDkdUj8dRrBV8WTMg8sa85AmDAjRCRVwBPL618S5vqJKp/mBSvqVirq5hNMd4T25KqBq3mzZLryrgzQp7KZzYQVgSxkvO8Kz99/SXtzAm89eHHqy1fHwpEjV7Yff5o6LnISAOgffpcM2o43NqHLfWfo9SPcZ2+uHyLe37jxbZzq7bH8cQTqe483apKwnSO6eia/fIjHixiwbaCz5wLq1KcJaVKpbTXyP9FIOrptd2vH20M+z2RtoCNZz6j+9uHkc8JfxhX9zztuiAGtOb2dxbzzY04VvnG0Q2t7i/CYDzYVvArNzh5UzAWdy2c7ZDU+N4VlzNGtoEjC4Dt3X+muSo4wfOE81sYi3s9+aZ1n/O0c1W31deqrfTd23n6qOp+4pWky+Ew6Do44pmrtIlnz4h/o1T59B6Fgok8sX+VJeOMPzoER7YGht1/g2gtiW0izBcrX+bKBb/bri336unWlay8fnefP9rYfbp12W/lz9n3rQesoJktdgNOxohhH6CjOnIVTGRnABnH7k+N7cs/H96XBw7jLO28aE2N3Ob12uGq0O7BvrPXlYeRWfBULlMwGI+bfLfvly8EYh9a3x52ljSSANi5oaD5reAYrb169uicAAEd3PbBB+7sEPxG6TyUEASj5m6K2n22xVqYMZ1eWnaDIJlfd1QsNM8NO6McSQvYyzfXBCe4DxUBxpDLNa/zITsrLvjpNfeQRvgbzv35uD8nbQ8q0BqOirshpH0WE2Ox35e0ga29VnFoFzaaM4Dt5c84rlDMVQUIqN3KEOF6qOh1z/gtXCD4jcdWp+76rdzlzhlBRIGrVCeg5g8CMb5fHvbroQdA96FFxeIkt/iZiS6Mw77xs9A0Ym6Hn7t+69XTrXX2rk3m9TdfuKMta25YRLsTxAiTKXNP8Jh8jwqgjL4TOPwKoOevCU7g2jeMo73wmQepCGnNHbB3U648mIXDBUF3Xs210WkLh0s9udW5+xkBEQAtY/TtYb8eegA0xvtMcISrMvAhg6DaOzS57SMyqnrPtXuZroyGa6PTFg5d6ZfGzpogkFFXoGXGiFUwoQZAt0WeqkUfPm+ECK6z8w8RqHeqfo9u0O6NVq8t3KkGCn/WIVDR64IxUIUelcdCDYA+wx99aI2D5QjKXWZuX7RrglD1zvpR9ZutTjUwf4EP4zCYMhPBY3kicPcjlwf9Wtgt4IrgKDVU/xBYy/fuCEJlRG5y1m9+utXAc27SWjAdNRRZglJTE0izmS8P+rXQAiDTv/0V8/kNAQLoPN3zGgpPZ9Dj52db3L0dA27SurM3kJbwpNxewM5RK4yiPlVnx6iWB/1aeBVApn9PMvI5VQcE4QY/2PcVHhXdLhZyXKMVM529gbSEp2EM7xMBMQgi7vtlcFEhtADI9G8fOW9DgAA8r3mV6l9Y9EGhsEDLN6ZcS7g7JVwTjM1VAVkJM1qh2KgJbCfcnB30a6EEQNq//Wjt1ddfbgowAmtfQqRy202fMuUbby4EFguNC1zZNZm95g6LoUeoV6t1HjKG7wIMJQD6aiqCI1TlcwECYO1LONT419w5M0EiuA9o2xK+wL7ACRi5ThVwNFXDg6BqtBVAT4XJpGMK+RwHzzFSu/rH2pdpdfb7Pf8fG4LEcRVbQuDYSnutVxXBULb6xZ3A9ntl0C9MHQDbh9eNLAr2cfMHgqL6Ny2tqVGGPRKOEDg+9X0WQ4/CKhgZdjxv6gCY81oVwVHc/IEAqP5NS2tu0pdrn9KBEDgehkFGYxVMx6Dvk+lbwCymPK5eKC4w/IGRqP5NoxP+qLSnSzsEGuH9MyCGQYbzcj5nANvq4QfAUqVSMtz+cYSKbjKBiFGo/k2D8JdmxWLzGtPBwaiRjwQDNRoFvo9k8G0gUwXAVitXERyhXP2GAKj+TYrwl3ZuOrjVyl9hhcdo3Awy3KlTrynGiDuV5oVfAWz5LH8+SmscRscoVP8mRfjLioNl0VwbN4pPF26gzi5AvodUTCRnACuCfbZtURVgBKp/kyD8ZY0LgZ7KFcFwRinEDKWZD4C+H3IA5PaPPozcE2AIqn8TqauRK4S/7HEdFftgfVMwhFksVSplQV+2+lWTjFOVcAMgt38cpzXWUWAUqn/jy3neNV5b2bX7bOsuk8HD/dLIrwr6MkoLeNB9wBMHQPsvpOx8iBFD9Q9BVATBqdz+iTu1M89NBjMUMhifx0MY/VHQ10QBkPUvJ71RyPMhhaEWLq6scWxiDDb8cbcvHHeY31NzTdAXS6EHU2UX4CATBUDWvxyn25xPwii2FUH7NyB3nSLhD4e1NyzYhwJBX9wN3J9hCMS9oZb7/fRkAZD1L0fY9i+7/zBUZ1cX1b9gtFbI56n24AT3UMCS6P7UcC6/H66DG2yiAKhqFgX7aP9iFN8oVyYGU2fdC4ax1WGmgvswhnOA6M8YLff7+bEDoFtjYb/RCID7aP9iOFa/BGdEbvN6wjDt1TDK0N1Jpsw5wJO4D3iwsQNgzmtVBPto/2IUL99cE4ykqvd+dis/gBEK+da6cMPDCY3WLutgjrHVL75PBhg7ABrl8unDaP9iJNq/AbhzfwvrAgTQvuJLWbx/At05jGGSM4AVQRftXwzH8EcwnXN/mzypI7BivumqxXzPHGIMBZrjjE8FUMK4C5jr345SlScCDMHwRwDKuT+MjypgP+5aOM4BHtbycwRACecqOMrLh6gY2r8YiOGPILTGvj9MiirgSc3mDp/TCGSsAGg8w5j5Pq21F5MCAzAwNZpr/QowIaqAJ7U4B4iAxqsAGuUbq0tFqgIMo4b27zC0fhECqoBHeWLeEyCAwAGQ839HGU8/F2CA9r5MBqaGoPWLcLgqoCrruHqMeBRqEMg4FUC+qQ559fWXnP/DQJprso9rCFq/CJOK8n68j0INggkcANn/d8BdVC/AEJ4K7d8B7If1Bq1fhKlzHps7X7tKpUqlLMAI41QAK4IOX2k3YCCuSxxGa4VC7rYAYaMNvG+vVeT9ByMFCoDddRZlQVuhmKsKMADt3yHshzTVP0TBYzBvn/H9sgAjBAqAhUKDp4l9WuMDDMPYFxXrkvpi8APRoQ18wFMtCzBCoADoG9q/Pax/wTBM/w6mRmj9IlKqPtsZxFUA6dj15LwWN6MMEOwMoFH2CnWx/gXDsPx5EK3tPn+0IUCEPAb0OpTP7B71DAFwQGU8UACkonGgmDtdFWAQlj/3RfUPs5DLtaoCi9CD0UYGwDOXliuCNrf+pV7dZOM8BuJhqR+qf5iN9tVwnAN0SqXKKiEQQ40MgNwreMB+uD8RYAAelvqj+ocZ4326rU4AFFe4oRoqA65KHBkAlQXQ+1gzgGF8o7R/T6D6h9kyYrYF0mzmywLxW17mA6ANwRMGQJGyoK2zZgDoz77IqJYfQ/UPs5ZTIQCKu6+A4OP4VAAHGhoAS5VKiRsNOrj+DcNw+0c/VP8we7byVRPY4g3Bx7Gf3fw5DDA0ANoXEh9oXZz/wzCsfzmJ6h/m4fU37UX9mR/W830CoEMQtoyp9fvpoQHQZ6JxH+f/MIzhrOwJXJmI+dHMB0AqXx3G0AofZNQZQJZJdnH+DyNUBPtUdIMrEzEvtupTk4yzr0GCj7S/F85KxhnV7/r9/NAAyABIB+f/MIw7/2dfYmXBASP3BJgTI/0/8DLF+P9OgCEGBkAGQA7TPwgwQKHQ4HVyhG7vPn/EJCaAubMPA2XJONUxr4JjAOSALSFvCjCAb2j/HqZU/zBvSgsYPXRnzIAzsQMDIDeAHMjnz1DNwBDKAMghDH8AiAPXyRSIZ/zxAiA3gPToNvf/YhCOShxj5HOGPwDEQWOvUBaI8cesADIA0mH/HKj+YSCOShylohyXABAL6rED0CkUG+MFQKoaXYYF0BiMoxJH1Ln5A0Bc8P7cUa9Wa/1+vm8AXLi4wh/aASqAGIijEgeo/gGIE5Zhtw08wtY3AHo5vyxw6qyzwDAclTiEajniwmhZAC6zEHcn+6Bf6RsAW0apAEr76YHwh4EYADmqUFygAoh4UMMSZPV+lIxTQwVQ1YxXARRScxcLoDEYAyAH3G05TMsjLvjgdwV5k/nXoxEe0MUM3onZNwDS1uowqlUBBuCA8QHfyOcCxAS3P6C7A5AHAR18LWLfAEhbq0NbbJPHYJ6yYb7HMzwsIU54bdrP8UxXAOnQdAz7PjgRAJkA3scACIYzylGJNq3xWkFc8BnW4Xma6QCoyg5AJzdkluFEAGQCuIMBEIxCm6nLGM7KIjZY/tuhJtsdLIZZOwbdAuKcCID8ofUwAILBOudLaDM57P9DnHA2F110aKS9naE26Nf6nQHkD83xqQBiMO6YPILXCmKD5ewd+XyzJhnGMGtbfdh2hhMBkPH5DttGqAkwAEcl9nFWFvFCF6tt0PVfWcCO1p7BS6CdEwGQvTkd+fwZPtQwUNPXsoCzsoiVU+9/WuZohjP8gz/tmADuMua7Yb98JACyN6dHt1lqi2FYAdNhHxi5/g2xUSg0+OCX9gRsTTKMc6Bd3vAH9CMBkNTcNSI1A6yA6VKPCiBio+V7nwnE+JLpa+B4QO9QHaMFbGhrdXi0tTCCUil3WJaOmKkI+AzjAb1t1CqgowHQIzW3UdXACMYwYSYMgCBGOgug+QxzRlV+0s7wINA2apbh+BAIqVmoamA4zsp2MACCWPH8NUFblpdAcxPMvvqoWYYjAZAVMB1UNTAMOwA7sn7OCPFiDOf/ejK+xYIAKMEe0I+2gPmDEzcBLMAQXDXVxVlZxMSZS8sV2r/76lneYmFYBN4W5AH9eAuYtpYa1r9gKC4Z7+KsLGLCN3pV0Jb1oxn2/ZlClrSDcHXU79kPgPTNe7gDGMOxBLrDMz4PS5i77vLnNUFXdj/DuAHkQG6cFjBtrQ4/w4dnEYyyAqaN23IQBzmvVREcyPA99q1WriJoy+fztVG/Zz8AsgOwI8dkI0ZQ4WHJ4bYcxIFtdd0SHJbZzzDfsP6lq16vflEb9ZsOAiA7ANtsEOZDDUMZ4xEAM37XKOJh4eLKGsMfR2R7NycLoNuCngM9GAIxWhawAgYj2QrgWcm4rN81inig+ndUlgdA2uf/WADdFewc6MEZQD7UhKoGEAw7ADFvVP/6ye4ACOf/DvHHrQBysJ2qBhCQfa38RYA5cZO/VP9OMqpVySjO/x0xXgDkblNxfwg1AUYwomXJOPtB850Ac+LlWreo/p1UzJ2uSmYpC6C7gh5lawdA7jbt4EMNAOKNvX+D6HZWJ/PbFWH2/7VpgAXQPe0AyN2mHaqcAQSCsG+2TMtjLmz177HgBPvB/0Qyil2QhwU/B9oOgCyB7lBawAiE1pPnsS4Js3f64jKt3wFUzKZklPHMZ4K2cc6BdgIgd5u2sQMQAOKp3fpVWRf0tfN0qypZxQDIPm0FL2S1AyB3m3awAxAA4qdUWS3R+h1snHNfaXPm0nJFmGHoGWsReLcCyB+eRfUPAGJor7F7h9bvEL4+kIzyjV4VtI27CLyzBoZbQIQl0AAQP91zf2uCgQrFXFWyqyJoMzLeIFCnAsgtIO4cJBVAAIiRhaWPr3LubxS3/uWLmmRQp/1LZbjHBrrqmL8fbUwAA0BsLFxcWTSidwVDGTGZbf/a/+6rgn35/JnxW8DcbMASaACIi+5Vbw+Fw/0jvVHIZ3f9i/FY/9LlBoHGXQTerQCyBobFtgAwfy78dSZ+ae2Nlt32r6sQ8z1yWPAF0D29FnDmA6B6Xk2AQBgY8n0eGhE+wt941Mg9yShbIb4u2DfJInCvew9w5nnGpwIIBMTqKITNVXS8XPMF4S84pn/RM+75P8d7/foUb+TCLSDAOFSU9w2E5q0PP1k1atyiZ76vgjLyOdO/cCY5/+d4+XyzLLBPUg0CIAJhZZC4J6Z/J0AI3vxg5XrL9xn4GFfO25CMYvnzceOf/3PygrZ6tVoTIAgGhsQYfVuAKbjr3RqNnVtGzA3BmLT26usvMzv9K7R/j5jk/J+TN+4eYDUCIBijNgBm/SWjmvnl8ZicO3u+19i9a1tXZ1Wye4/tpGxoHuvGhzRZuLiyZmj/HlbfebpVlQlQAWxjqhNjMPqjZD4B0q7D5GzHxVXR1wQYlxrav4eMe//vYZ7xSNIWZ7qAsfC+AWC22gvCaf8e5evEN8FwFZxwqB9jUq4NdGwbrywAMCNevrkmOGKaVUCecgsIMBZujeloNvNlAYBZYfr3GK1NswrIM8YjABoqOgjOM+yMdIxqWQBgBtzwB0dPjpp2gIoWMDAm9XhgaDOyKAAwCwx/nKBqJj7/53j2DzXzC11tJeM7AQKyrc+aQIzP0ziA6DH80dfE6196PDWscwDGcerUa1rAjup7AgAR83KtW4KjjEy9C5IWMDCm7g4zQqCYsrvNQQAgIq76Z99rVgVHqOjUN8EQAMUVMlgEjXExCOI09nbLAgARyXmtirB4/oRCcWH6AGhEywJgPGom3r6eJr6aigBARIwK7d9jVKVar25OXYSgAghMon0dHDwxnAMEEAlWvwwwxe0fhxEAxRVzWOuB8RihAugY8SoCABGg+tffNLd/HEYABCbAMugeBkEAhI/qX3+d9u/kt38cRgAEJkMFsKvZ3GEhNIBwsfi5v5Dav45HwgbGVyg2aoI2I8qKBgChOXNpucLi5/7Cav86VACBCXR2AbI+qM0wCAIgPMZw9q+fMNu/DgEQmBSrYNrckzrnAAGEgerfECG2fx0CIDAhFcMd0l17rVcVAYApUf0bLIzlz4cRAMVdas9EJybge1QAu9SwEBrAdKj+DaaiG2Esfz6MACjtA/0EQEyCANhlDBN7AKbjG70v6EvVhNr+dQiAwISYBD6i5J7eBQAmwN6/YbS283SrKiEjAAITcpPAqlQBe3xaNwAmxK0fg6lIVSJAAASmYIz+QdBhlDYwgLFR/RuuUMjdlggQAK3GXoEVFpgIdwIfZsq0gQGM49T7n5ap/g0W9u6/wwiAlnqGAIiJeEargn3cCgJgHJ7XvEr1b4iQd/8dRgAEprD7/JGrADJF3sU0MICgXPVPVNYFg9TtZ8yGRIQACExJWQdzGNPAAALxci1av0OoaKiLn49zAZDqBTANNQyCHMImfwCjvPXhx6v23WJNMFBUwx89NgByCwYwDU+jGdFPKu4GBjBKy/fuCAaKcvijhxawuDOWHh9WmFgu16oKjthr7twQAOjj9MXlWwx+jBDh8EcPAVBcn50pYEyOhdB9GLkuAHBMd/CDB8ShtBbl8EcPARAIhXkiOIxhEAAndAc/KLoMEfXwRw8BEAjBrF6wScIwCIDDujd+rAmGKhS8ezIDnm1/1iTjfJ8WMKaTzzdpAR/jhkGoAgJwuPEjGFtM2Ih6+KOHCqC0p20IgJhK+xygMA18HFVAAE6n9cvgx0hGZlL9cwiAQEh8kc8FR1AFBEDrNxi3+qV7u9RMeEb0O8k4NeasAFPKMQncF1VAILto/Y5hBqtfDqMCCIRk5+lWVbhZ5wSqgEB20foNajarXw4jAIqrUOjbAoRA1cz0CS4pqAIC2UPrNzg1Eum1b/149j+1Jhmnnvw7AULAOpj+qAIC2ULrdxyzr/45VAClXQFkChih6K6DoQ3cB1VAIDto/QY3j+qf49k3ZT6s2EqOkLh1MPblzDRwH64K+NaHn6wKgFR784OV67R+g9JaoZiryhx4nlECIHcBI0Semg1BXy3f3ClVVnm9ASnlWr/qmbuCYNQ8mNXi5+NoAXfwgYTQ0AYexpT3mjtcBA+kkHu4s63fx4KAtFbM5zdkTjyb1GsC+41bKQsQAtrAIxi5Xqp8WhYAqdJo7HDubxxzrP45nvFpAQNhow08VKnRaN4XAKnhzv0ZEar7gc23+ud4LT9HALSazXxZgJCwFHo4NxDS2REGIOk49zeBOVf/HO/Uqdd8SFlGtSxAiFgKPZxRBkKApHPhj3N/45p/9c/xOueV4PtMAiNcLIUeqbS3t0MrGEgwz2ve4dzfmGJQ/XO6U8Bak4xTZRIY4XJtYPt9tS0YTGV1YenjqwIgcU5fXL7lXsOCMcSj+uewBqZLjTkrQMiMCNPAIxjRu0wFA8nSXvassi4Yi7v1Iw7VP6cdAFVYBWOMvi1AyIr5JgejR2MqGEiQ7tDHumBM87nzd5B2ALRP4N9J1qlSAUTo3BlbFakKhnJTwW9+sMwKCSDmDg19cGxqTPO683eQTgVQfQZBOMSKiKjG60UfV+rJnTOXlisCIJYObvrg83J88ar+Ob0KIAHQfm+zkgJRYBgkON/ofc4DAvHUmdon/E0i5+lNiZlOBdBnCrijTgBEJHwj7AQMxJQ5DwjEDxO/k1PRjZ++/jJ2a8HaAdDL0QJ2uA0EUXmj0NwQbgYJxJ0HbH/YAIiFbvhbF0ykUMjF8hhQOwD6La8m4DYQRKa9cF3lniAY+2HDfkBg/lj3Mh1X/YvL2pfj2gGQ+4A7jOFsA6LjN+Ox/DMp2A8IzNdbH36yyh2/09BaXKt/TjsAvv4mnul01lgGjSi51xkrYcZS2mu0HhMCgdlbuLiy2PJ9zuNOIU5Ln/s5dBMIgyBCCxgRYyXMuNxQSOuhAJgZt+vPqGHX31Tit/bluP0AqGoy3wY2RssCRKi9EoYq4FiMmMWFpRUqEcAMsOg5HLb6d0Vibj8AGpGaZB5nABE9qoDjsyFwjclgIFoH4Y/Pwmm4wQ9b/Yv97teDCqAYroMTt+m8UhYgQlQBJ6SyznVxQDQIf2GJ9+DHYfsB0DecAXT2WsVFASJGFXAy7ro41sMA4SL8hcd2K+7FefDjsP0A6Bmug3OM75cFiBhVwMkZ215xE4oCYGqEvzBp7ednW4lZm3NoCpi7Sh2PSWDMCFXAybkJRUIgMB3CX7iKhdxlSZD9AMgy6A7j80LAbFAFnErJhUB2BAKTIfyFTOO986+f/QDYXQZNCFR9T4AZoQo4FRZFAxNw1XMv13xB+AuL1or5M4m7McU7+recA3QviFJllf1HmAmqgNMyZUIgENyZS8sVljyHy1NzrV7dTFx+OhoA1XAO0Grs7ZYFmBGqgNMiBAJBuAl63wjhL0Ru5597kJcEOhIA2QXYlRMOl2NmqAKGoRMCGQwB+nvzg5XrboJeEKLk7Pzr50gAZBdglyEAYrZarfw1wZRMmelg4CR3i456JnFn1OJOTfIGPw47EgDznqkJmATGzLWHsGgFh6E9HfzWh5+sCgA57e7RVlkXhKp73duGJNiRANhoFDgD6DAJjDko5pvuCZ1BrOmVWr7/kGvjkGVumHFhacVN+q4JQuZavws3JeGOBMDuKhgwCYw5qFerdRWqgGFx18a51pcAGeN2/O01dl8YMRyHiEBSp36P807+FOcAnWZzhxcOZm732dZdBkJCZFtfC0uf3BEgI9yaF3b8RUjldlKnfo87GQBZBdPWYhAEc8JamHAZ8W8sLC2zJgap5yZ9WfMSJa29erq1LilxIgCyCqbDE8M5QMxFey2MmnuC0BiRCrsCkVbuyJIb9mDSN1pJu+t3lJMVQN+jAijuA8OjAoi5KeRb68JASMg6uwKZEEaauPN+jcbuY4Y9omUfIm8meeVLP33OAAoBsM0sMgiCeWkPhBhN/JRZ/JiymxBmOARp4B5m3Hk/hj2i5Va+/PxsK3XV1RMBsFBs1ARtXAmHeXI7phgIiYjKug2BD2kJI6kWlpbvuIcZ4bxfxJJ928cwJwKgqzwwCdzhq6kIMEfdG0JoBUdBZZVzgUga1/J1Q022JcmeyxlQI1fS1vrt8fr+LJPAbQyCYN7cbk52A0bJnQtsfktLGElw0PKViiB6KrdtJya1eahvAGQSuINBEMQBuwFnoL0vcOU+1UDEUedWD1q+M2VkM00rX/rpXwFkEriLQRDEA63g6Bkxa64lvHBxZU2AmLDfj4udWz1o+c6O1orFfOqH8LwBP08A7OJGEMQBreBZMWWj5r67PYSHP8ybO5pgvx+51WPG3L6/tJ77O6xvAGQS+AA3giAuaAXPjrs9xFVd3LVaAsyYq/otLK28cEcTBDOVxn1/g/QNgEwCH1DDYVvEB63gWTJld60WZwMxK+0bPbpVP3b7zZ6q3kvjvr9BvCG/9kTgDod/JEBMuFawp3JFMDOcDcQsuGqzqzpT9ZsXre0+fZSpc5YDA6B90+McYEepVKmUBYgJ7gqeh87ZQJZHI2y9CV9Xbeas37xoLW33/AYxMADmPVMTtDVahYoAMeLuClaGtWavvTy6szeQIRFM680PVq7vNXa+ZcJ3vtK87HmYgQEwl2tVBR2+TxsYseLO6bZaedcK5jzgPNg2nWvX0RbGJFy71w15qGfceTMeJObIDX2kednzMDrsF08vrXxLSdrR2qtnj84JEDMugLjWpGCOtOapueZa8wIM4aZ7bbnpDjd5xITK7bQvex5meAC8tPzQxuNVgRQLZ96uVzeptiB2Fi59fNcYvS6YLyObbnlsFltJGM7d3+vlWrfsN8maIB7cTR/PtzI9UDdsCliMYRK4p9HaJQgjlnaffnWD84Ax0D0fyNoY9PTWurj7ewl/ceJu+jhzTTJuaABkEOQQFkIjxjgPGB+dtTEEwSzrBT834NFd68I5v9joTPzS0RvRAi5VKqW9Rv4vAuEcIOLOHSzvrJJAnKjohqp5wBnB9HPBb29v57r9H91N9RL64qdeLOQvcEyjQ0f9BgZBDhQLzXP1arUmQEwtLC3fMCJ3BLHTvsbP6IPd5482BKnSefjSq7R54y3neVd++vrLTUFbbtRvKLzz7gX7A+1Py5fcHxrfv+SsFWKr8cPLb+xr1lWqec3GT9mdE7T/+6wVf/vujwvv/nX9de1PtO0TzAW/wm/P37cPXevCay7eVG7vPn3094J93qjfwI0gh7APEAlQLDQYCom1zq0ie43mC84JJk/vfN/ppeW/uCMXrHRJgIyvexlkZAuYc0VH1F8923pbgJjrrp3gaqmE6LWHC8WFTQ6nx1P7s9AXd76vIpzvSw7C30AjA2B3EORb4Ru+TY1eyOrWcCSLWzprK03u4Y3XboIwNBIf7h74vb38VYY6kkofvHr2aE3Q18gA6CwsLVPm7nLXxvz8bOuuAAnATSFJpjVXGSQMzpZr8f7S2FnzRD7jcy+57IPU9u6zRxcEAwULgNw0sM+9Ie8+27osQEKcvrS8bp9cbgkSjDAYJUJfurjwVygssOtvhEAB8K0PP15t+fpQ0Ma1cEgaHuJSpW4/4DZtqH9SKOaq7DSbTPdM30eqUiH0pUlv0TOvi1ECBUAWQh/jeVdesUsICXN6aWVDxFwVpIqrdoinVTX+5/n8mW0eTvtz5/kae4WKqP+REXVXe3KmL3UIf+MIFAAdFkIfUNV7u08f3RAgQdyDXKORd+d52VeWYu2JYs/btu3MJ7nc6WpWA+HRwOdV+PxKO8LfuAIHQFpIR7AOBonUqeYXXvBhmB2uQmiMqRm1gVBlO41VQhf2Wq3ioi/ykWn5ZVa1ZA3hbxLBAyDThEd4Kpc5jI0kYkcgOkMlpuYqhb7vf5eUYNgLek3fL3ued1Z8f7Fb0SbsZRbhb1KBA2DnQ6P5raCD5ZJIMEIgBnADJjX7fVF34dAY/0f1bVj0bAXR13qh2KhHdR96t2Vb8nJa9lumZDxTVmPO2s5TSVRtyDMu5BH0cAjhbxqBA6DDOcADrINB0nUf6mw7mA9VTKK9mqbeDotdxtgAqWZIFVHL+793/2uCHSZB+JvWuAFwgynCA6yDQdJxWwiA5CH8hcEb5zerkapgn1scKkCCuWsN1airZPMgAyABCH9hGSsAFooNdt8d4rbGC5BwhEAAyUD4C9NYAbBerdalfUAYjtse764QEiDhCIEA4sytMyL8hWusAOio+p8L9tEGRloQAgHE0cHdvoS/MI0dAD3lHOBhtIGRJoRAAPGiDzrhj4HLsI01BexwL/BJTAMjbZgOBjBvXLsarbErgO4cYPuuSeyjDYy0cZVAv5W/wJlfAHOhcpvwF62xA6Dj7pQU7KMNjDR6/c0XNb+Vu0wIBDBLRuQmN21Fb6IA6FEBPIJpYKQVIRDADNXV+Nd+frZ1VxC5iQLgztOtqnBI/AjawEirXghUkW0BgEhozQ2g7T7/HxuCmZgoAHYo62AOoQ2MNHMhsFBoXrblbpbBAwhZZ8GzO3ssmJmJAyDXwh1FGxhp5wbAXj3fuqJq7gkAhEBVqsXCwgV2/M1eTia08O47tZbv/Z1gX8vs/dL4/mVVgBRrfP/tF4Wz590KqYoAwIQ6a162/vZ17Y+vBTM3cQWQdTB9GKUNjExwE3r29X9TAGACbtKXNS/zNcUZQNbBnGQWz1xargiQAbvPtu6qUXYFAhhH3VO5zKTv/E0VANVXDoQfY0RXBciIzsJo1sQACMINe+QvdDeJYM6mCoCdiR3e+A8zxlxlGARZ4iaEi4XGBSaEAQymDxj2iJeJh0B6imfPnbP/w74v6DllzN4/7X3/siZARryu1V43fnj5e4ZDAJygcvvVs60bDHvEy1QVQEeFNvBxxsgtATLIDYfkPHNFWBQPoHvej2vd4kklBKeXlv9if6DteUixcObtenWTD0Fk0qn3Py17udZj+zhUFgCZY4tD24VC7got3/iaugLYwa0gx+01dxhvR2b1zgWyNBrInvZ+v2ePOO8Xc6EEQE/NhuAoI9cFyDC3K3T36Vc32BcIZEY953lX2O+XDKEEwHy+6e7vo915VImdgEBnX6Dfyp9jYwCQXp0r3fIXfvr6S+YCEiKUANi9FYRLnI9hGATooCUMpFf3SrfLtHyTZeo1MD3F376rosIS5KPKC+/+x3uMvgPdVTHff/uFfa/4zn5iLAqDY0DCac1TsS3frb8XJE5IQyAihWLDlX1pAx/DMAhw1O7zRxvu9hC6BkCCGdl0i5251SO5QlkD07OwtPzYsAT2uPqrZ1tvC4ATTl9aXheOSgBJUref87e5yzf5QqsAthl9IDiOYRBgALcglgERIBl6gx6Ev3QINQDSBu6PYRBgMDcg8urZo3PuuigBEEeu6neTQY90CbUF7NiWzkPb0mEY5Bh3HQ5nJYDhuEEEiBdX9Svk89cIfukTbgu482/Imoc+jCihGBiBaiAQG1T9Ui70AMhS6P6MMVdLlVXWXgAB7J8NVGGpLDBjKrpRLJw5x1m/dAttD2CP2/VVPHvu39tvofcFh51qmb1fGt+/rAqAkZp//lPdvl5+z95AYFa6e/2ebbG/NgNCrwA69umBp/Z+jFynCgiMZ39vILeIAFGpu2MX7PXLltCHQHpOLy3/RXhiP8GdqaCsDkzGDYnk8s2HxsiiAJgaQx7ZFUkFsE0ZBunH/oF/JgAm4oZEdp9uXVCj19gdCEyj3e69zJBHdoV+BrDnjXfOu2rXmuC48htnzz/Z+/5lTQBMpPHDy237173C2fOui+GqgacEQBBuuvf/tJ2ov+VzKNsiqwC6cwT2nbkqOIHF0EA4utPCF2w1g1uIgOG65/yY7kVHZBVAJ//O+bdtCPxUcBxVQCAk7WnhH15u5n791w/UM+7ebc4HAod01rrk//anf/5yk+le9EQ2BOKUKpXSXiP/F8EJrjq6+2zrsgAIVXdQ5L6ttFcEyDA34GE/a24z2Yt+Ig2AzsLS8mMjvBH3w/VwQHTOXFqu2PeeWwRBZA3BD0FENwXcpVzpNJAxelUARMJ9+LkJR/eg5T4QBUg5933em+wl/GGUyCuADjsBBysW8ucYwQeiR0UQaUXFD5OIdAikp3D2/JtCG7gv3zelxg8vPxcAkXJDV43vXz5wA1jGfWQyLIKE61b8rtmK322GCjGumVQAGQYZjiogMHtuWMTLtdZFDEcxkChuqlfVPKDih2nMpAL4ulZ7XXznfMV+WRacQBUQmL3D62NsELQPw96vhKMqiC+3x++/Fgtnrvz09X//PRU/TGsmFUDHnb/xjTwW9EUVEJi/hYsra0bdonZTFiAGVHXbN+bBG4UzG/XqZl2AkMwsADoMgwzmSvq7zx5dEwBz13lg1TXaw5gXBjsQtdkGwEvL68I1aANRBQTipb1U2mtVqApiRlyb914xf+Yu1T5EbaYBkGGQ4agCAvFFVRBRodqHeZhpAHS4GWQ4qoBAvJUqq6XG3u6qeOYqOwUxKRf67GfhE6p9mJeZB0CGQYbjjmAgOVyLWHPNVU/FhUH2CmKUdovXs+/zVPswbzMPgA7DIMNxRzCQPO29gvnmmn1T/YwwiEPqqvpAxWzyvo44mU8AZBhkKKqAQLJRGcw8Qh9iby4BsDsM8q1QBRyIKiCQDr1JYs4MplvvTB/tXSTFXAKgs3Dp47vG6HVBX1QBgXR668OPV1u+t2q//IjVMolmq3yy7Rv5nCXNSKK5BUCGQUZTo9d2nz/aEACptL9n0DOfidFFAmG8UeVDmswtADqshBlFa8XCwgWeLIFsWLi44s4LLhII48EFPvv//+DO8uXzZ7Z5L0aazDUAUgUMQOX2q6db6wIgc1yFsFBoLPrGq9gw+B5nCCPlVrRU7Z/xk5xt7RL4kHZzDYDOwqXlF0zJDVUvFs6c440IgOMenFv2PVNFF1XNWULhRNrn91x1T3zZLhQb1Xq1WhMgQ/IyZ7YC+MCmUALgYKVG45VbmXNTAGRe9+xZ9fDPudaxl/PLrXbbWN6z76llHqzbXNCriTHbvg17ec/UcrnWNmEPiEEFkJUwwXBFHIBxuWConim5iqGnWnZtZPvTpZSFQ9sdUdu+Ndu2Kvqdb0yNoAeMNvcA6LAYejTWwgAIk7vTuNnccW3kUtPXsq2UldSYs9IOijYqGvejcQ/m83o4bwc7+89XNyI1+89WN6rfqa81W+2s+y2vVigu1DgeA0wmFgGQKmAwLIcGMA/2Pbrsfmw28+XezxkbGve/9sabVnYhrve1C3M2bNbtv1+9UGy0wxyVOyB6sQiADouhg2AtDAAAmJ4nMdFqFu4KRjDlvebODQEAAJhCbALg62++qNl65KZgOCPXS5VPywIAADCh2ARAx/7D3BOMUtrba94RAACACcXmDGAP18MFw0AIAACYVKwqgI6q3BaM5Bu979Y4CAAAwJhyEjN737+sFd85X7FflgXDlFpm75fG9y+rAgAAMIbYVQAdqoABMRACAAAmEMsA6M626bG7LtFXqdFo3hcAAIAxxK4F3PPG2fPfGZE1wSjl/G/O/9j888tvBAAAIIDYTQEfxkRwYPVi4cw5bggBAABBxLIF3MNZwMBKe3s7tIIBAEAgsa4AOlQBg2M3IAAACCLWFUCHKmBw7AYEAABBxHYIpIe9gGMp+X7zVOOHf/0nAQAAGCD2FUCHKmBwRvwbZy4tVwQAAGCARARA9gKOh1YwAAAYJhEB0KEKOA5TbjRe3RIAAIA+Yj8FfBgTweNhKhgAAPSTmAqg02rlrwkCoxUMAAD6SVQAfP3NFzVbtHwgCMiUWRANAACOi/0amONyv/7rbfX8NfvlKcFoKr/jrmAAAHBY4gJg889/qhfOnn9TOAsYmKq8v/DuX//+de1P3BUMAACS1QLuKeabd+0PhJngSo1Gk1YwAABoS1wF0Hldq72mCji2Mq1gAADgJLIC6HSqgFoTBKae3OGWEAAAkNgAWK9W6znPvykYC6thAABAYgOg89PXX21yRdy43C0hu3cEAABkViLPAB72xtnz3xmRNcE4FjkPCABAdiU+AO59/7JWeOfdc/bLRUFgrIYBACC7Et0C7vFbuXVhLcy4SnuN1mPOAwIAkD2JrwA6LIeeWMn3m6caP/zrPwkAAMiMVARAZ+H8O9stP/c39ksqWmMx73MeEACAbFFJEbfjzjfyWDCuerGQv1CvflETAACQeqk4A9iz83SrylqYiXAeEACADElVAHRarfw1wQTYDwgAQFak5gxgT3cgxLW2K4JxsR8QAIAMSF0F0OGe4MlxXzAAAOmXygDIPcHT6dwX/GlZAABAKqUyADrcEzwNdx6weV8AAEAqpTYAOt2BEG4ImYARqSwsfcJQCAAAKZS6IZDDuCFkWiyJBgAgjVK1CHqQ00sr37q2pmASdTV6eff5o20BAACpkOoWcI+nht2AkysZlYcMhQAAkB6ZCIDtG0LU3BNMyA2FtB4KAABIhUwEQKeQb60LAyETM2IWGQoBACAdUj0EctjrWu31qfK5/2WM/o1gQub9wm/PS+OHl08EAAAkViaGQA5bWFp+bJgKnoqnctm11QVAYJ1ztKfq9eomnQgAc5e5AHjq/U/LXq75wn5ZEkyqXizkL9SrX9QEQCCnLy2vi5FbKuom6rft166Svs2EPYB5yFwAdGwV8IatAnKebSpaKxZylwmBQDC9ANjnl+r2jXjbqDzJqbedy3nbvK4ARC2TAdChFTw9V8koFBYu09ICRhsSAPtph0LxvG1P5InfMjUqhQDClJeMctfE0QqejpsMbjR2XSWVPYtAuErtB1Tfr7REbrhH9dNLy+2HLmNMTTz5g6sWumBYKC7UeAgDMK7MVgAdWsEhMbL+6vnWbQEw0JgVwHF1KoZiakb1OxcOjfHr+XzThsNqTQDgmEwHQIdWcDiMLzd//petuwKgr4gD4AhaUxcOjQ2KOc/+6P+ovv05z/6cr/VCsVEnKALZkvkAyFRweFgPAww23wAYmG0la92FRfc37cCopi5eru5CY+/nPKPtlrOXU/fzgdvPLmxylhGIh8yeAex5/c0XNVsFvE0reHq+ad8ZzHoYILnsg7Bx5w/L7b9Td8LD/j/f3/8Nrmpg1LS/bvlGxmErjlX7w2UBMHeZuQpumN1ntnVpZFMwrdJeo/W4s/AWAADEFQGwq1hsuklWJummZsqdELhKSx0AgJgiAHbVq9W6p3JFEAJTbjR2CYEAAMQUAfAQN8Cgau4JpnZoRyAAAIgZAuAxhXxr3a1MEEzNhsC1haVPCIEAAMQMAfAY1wpWQys4LEb8G6cvLsd99QUAAJlCAOzD7alSkZuCcKisEwIBAIgPAuAAbjWMDYFVQThsCFxY+viqAACAuSMADtFq5VkNEyIjuvHWh5+sCgAAmCsC4BDulpCcZ64JQtPy/fsLF1cWBQAAzA0BcISfvv5qk9UwoSoZNY8JgQAAzA8BMAC3GkZFuMA8PDYEtu8NLgsAAJg5AmAAbjVMq5V3q2E4Dxia3pVxhEAAAGaNABiQOw+oRlkNEypCIAAA80AAHMPu80cbnAcMGyEQAIBZIwCOifOAUSAEAgAwSwTAMXEeMCqEQAAAZoUAOAHOA0aFEAgAwCwQACfEecCoEAIBAIgaAXAKu0+/usF5wCgQAgEAiBIBcEqd84BaE4SMEAgAQFQIgFNy5wE95b7gaBACAQCIAgEwBDtPt6q2FcxQSCQIgQAAhI0AGJLdZ1t3bSv4gSAChEAAAMJEAAxRsdC4wXnAqBACAQAICwEwRG5JtN/KXRaWREeEEAgAQBgIgCFzQyE5j6GQ6LgQ2HyxcHFlUQAAwEQIgBH46euvNkXltiAqJaPmMSEQAIDJEAAj8urp1jpDIZFyIfDFwtLHVwUAAIyFABghhkKiZ0Q33vxg+YYAAIDACIARYihkNtSTO6cvLt8SAAAQCAEwYp2bQuSKIFoq64RAAACCIQDOADeFzIgNgQtLn9wRAAAwFAFwRtxNIarmniBSRvwbthL4sFRZLQkAAOiLADhDu0+/umErgVVBtFRW9xq7L1gYDQBAfwTAGSsUmleYDJ4Fbg0BAGAQAuCMHUwGEwKj1wmBLIwGAOAoAuAcuMlgNe3JYNbDRM6UWRgNAMBRBMA52X3+aFuNMhk8I25hNGtiAADoIADOkQ2BG9wZPEOsiQEAoI0AOGfuzmDWw8yOWxOzsLT8mDUxAIAsIwDGAOthZsuIVFgTAwDIMgJgTLAeZtaYEAYAZBcBMCZYDzMPnQnhNz9YviEAAGQIATBG3HqYTghkPcwsqSd3mBAGAGQJATBmOjsClRA4a+0J4WVuDgEAZAIBMIbYETgfneEQro8DAKQfATCm2BE4L244pPli4eLKmgAAkFIEwBhzOwIJgXNRMmrucy4QAJBWBMCYY1H0HKms2xD4kJYwACBtCIAJ4BZF2zTyQDB7KqucCwQApA0BMCFePXu0piLbgjlonwv8ln2BAIC0IAAmSKHQvEwInB+3L3Bh6ZM7AgBAwhEAE8TdFtJq5bkybo6M+DdOL618S0sYAJBkBMCEObgthBA4P6yKAQAkGwEwgQiBscCqGABAYhEAE4oQGBNuVQwtYQBAwhAAE+wgBHJv8HzREgYAJAsBMOFcCFSjhMD5a7eE3ZRwqbJaEgAAYowAmAK7zx9tEwLjwU0J7zV2X9ASBgDEGQEwJQiBcdJZHM2ACAAgrgiAKUIIjBmV9YWlZa6RAwDEDgEwZboh8KYgFoxIxd0lzIAIACBOCIApZEPghg2B1wQxYcqdAZGV+wyIAADigACYUoTA+DFi1tyAyJlLyxUBAGCOCIApRgiMI1P2jTxmQAQAME8EwJQjBMYUN4gAAOaIAJgBLgTmPHNFmA6OGdbFAADmgwCYET99/dUmK2JiimogAGDGCIAZwp7AOKMaCACYHQJgxhACY45qIABgBgiAGXQQArUmiKFONXBh6ZM77A0EAESBAJhRLgT6rRwhMMaM+Dfc3kBuEQEAhI0AmGGvv/miRgiMu8O3iNAWBgCEgwCYcYTAZOjcIsKdwgCAcBAAQQhMjE41kCERAMC0CIBocyGwWGhcUJFtQcwdHhIhCAIAxkcAxL56tVovFJqXbb9xUxB7nSER2sIAgPERAHGEC4Gvnm9dUTX3BAmw3xZ+QTUQABAUARB97T796oao3BYkhFmkLQwACIoAiIFePd1aJwQmC21hAEAQBEAM5UKgitwUJMjBtLANgosCAMAxBECMtPts627OM1eE+4MTph0EX7BEGgBwHAEQgfz09Veb3B+cTJ0l0s1vT19cvkUQBAA4BEAExv3BCaeyzvlAAIBDAMRYereGsDA6qY6cD1wTAEAmEQAxNhcC2wujRR8IEqoTBBeWlh/TFgaA7CEAYiLthdHPHq2xJibZjEilsz+QQREAyBICIKbCrsB06A2KEAQBIBsIgJiaC4GsiUkHgiAAZAMBEKFwa2L8Vv4CE8LpwOoYAEg3AiBCw4RwCnVXxxAEASBdCIAIlQuBu8+2Lqiae4KUMGWCIACkCwEQkdh9+tUNhkPShiAIAGlBAERkGA5Jq4MgyLAIACQTARCRYjgkzUyZqWEASCYCICLHcEj6EQQBIFkIgJiJ3nAI5wLT7XAQXLi4sigAgFgiAGKm3LlAWwm8KUg1FwSNmhfuruG3PvxkVQAAsUIAxMzZSuBdv5U/x7nA9HN3Dbd8/+HppZVvbUVwTQAAsUAAxFwcOhdYFWSAKduK4H0XBFkhAwDzRwDE3HTPBV7mXGCW9FbIMDACAPNEAMTctc8FGr0m7AvMlIOBkeXHtIcBYLYIgIiF3eePNtgXmE3unGCvPfzmByvXqQoCQPQIgIgN1xIuFhrcI5xZpqyeudtrD5+5tFwRAEAkCICIlXq1Wnf3CLMqJttce9g38rg3PUxVEADCRQBELLEqBh2d6WGqggAQLgIgYqu3KsaGwAeCzKMqCADhIQAi1lwIfPXs0RqrYnDgoCp4+uLyQ24aAYDxEQCRCG5VDC1hnKCyun/TCPcPA0BgBEAkRm9KmJYwTrJVwf37h1de0CIGgOHyAiSImxK2P6wtLC1vG5Fb9uuSAIfYILhoK4OuRSz2+6QqRh8Uigub9eomi8YBoIsKIBKpOyXM4mgM1VsyvdfY+Ys7L8iNIwDQQQBEYnUHRM4xIIJAVFY7N44s/8WdF2R4BECWEQCReG5AxFO5TDUQAZXcecHO8AhhEEA2EQCRCjtPt6rsDMQEjoTBXpu4VFnlbCmAVCMAIjV6OwPV6DWqgZhAqdcmdmcGF5aWHzNNDCCtCIBInd3njzZcNVBFqgJM6GCApH0N3Ys3l5ZvsGcQQFqwBgap5KqB9ofLpy8tr9tP8lsCTMGtlrEPFIs2EMrppZWae7jwPP08lztdZb0MgCSiAohU4wYRhK+zdNqdG+y1iqkOAkgaKoBIvW418BzVQETBtYq10y4+Vh30tuvV9vceAMSOCpAhp97/tOzlWo9dFUeAiKnotnhaVeN/btT7zPj+DckwVanuPt26LADmjgCITKIaCMweARCID84AIpM4GwgAyDICIDKLq+QAAFlFAETmUQ0EAGQNARCQg2qgity0f8teNwBAqhEAgUN2n23dtdXAC9wpDABIMwIgcAx3CgMA0o4ACAzQu1OYaiAAIG0IgMAQvWogQyIAgDQhAAIBHFsZw5AIACDRCIDAGLorYxgSAQAkGgEQGBNDIgCApCMAAhNyQyLcJAIASCICIDClQzeJ0BYGACQCARAIQa8t7Klcpi0MAIg7AiAQop2nW9X2lXKcDwQAxBgBEIgAS6QBAHFGAAQicmyJNEEQABAbBEAgYr0gmPPMFdrCAIA4IAACM/LT119tcj4QABAHBEBgxo7tD+RaOQDAzBEAgTnhWjkAwLwQAIE5YlAEADAPBEAgBg4HQVWpCgAAESIAAjHiguDu063L3CgCAIgSARCIIW4UAQBEiQAIxFhvYpggCAAIEwEQSACCIAAgTARAIEEIggCAMBAAgQQiCAIApkEABBKMIAgAmAQBEEgBgiAAYBwEQCBFDgdBFkoDAAYhAAIp5IJgb6E0QRAAcBwBEEgxt1DaBUHuGgYAHEYABDLg8F3DBEEAAAEQyJDDQdCI3GRgBACySQVApi1cXFkzKrdETFmACLnzqO5IggCYOyqAQMb1JofdwIh9JNwUAEDqEQABtLmBkVdPt64cOidYFwBAKhEAARxx6JzgBRZLA0A6cQYQwEhvffjxasvoVTGyKsCEOAMIxAcVQAAj/fT1V5tH28NUBQEgyfICAAG59rD9Yc197aaHxTNXjZGKAAAShQoggIn0rpujKggAyUMFEMBUqAoCQPJQAQQQGqqCAJAMVAABhO5wVbA9Qex7qyLmqgAAYoEKIIBItSeIu/cPu72CqrItAIC5Yg8ggJk79f6nZS/XWrdffsQdxNnBHkAgPmgBA5i5wy3iM5eWK75R+7X5zP5tSQAAkSMAApgrdwex/cH9xY0jADAjnAEEEBu9G0eKhTNvt+8hVtkUAEDoOAMIINbcecGc16qwXzD5OAMIxAcBEEBiEAaTjQAIxAcBEEAilSqrpcbe7qrxzGfSCYMMkMQcARCIDwIggFQ4WDjNapm4IgAC8UEABJA6brWMEV21beLPCIPxQQAE4oMACCDV3LlBzTVXPZXPODc4XwRAID4IgAAyw50bbLV+qtAqng8CIBAfBEAAmbVwcWXRV1OhOjgbBEAgPgiAACCd6mCzubPozg7ayuBHNhAuCkJFAATigwAIAH30dg4abVcGaReHgAAIxAcBEAACcO1i+8NiZ++gLhIIx0cABOKDAAgAEyAQjo8ACMQHARAAQuBaxoVCY9FNGKua9zhDeBIBEIgPAiAARKA3VOKLVOwbbW+oJNPX1REAgfggAALAjPTaxuK5MJi9SWMCIBAfeQEAzMTu80fb9oftwz/nrq1r2SBow9FH9om8TOsYwCxQAQSAmOmFQk+1bCuF76VlSTUVQCA+qAACQMzsPN2q2h+qh3/OtY+9nF9uGV3U9l5CKVEtBDApKoAAkFC9QZNj1cLYDptQAQTigwAIACnTC4aqptRq7yiU9+JwvpAACMQHARAAMuRwK1k6wbA0q6ohARCIDwIgAGAm7WQCIBAfBEAAwEBhtpMJgEB8EAABABMZt51MAATigwAIAAhVqVIpN5v58vF2sg2A2wRAAACADHHtZAEAAAAAAAAAAAAAAECY/n+sv/W59por5gAAAABJRU5ErkJggg==";
1006
1111
  var DEFAULT_MAX_LENGTH = 6;
1007
1112
  var MAX_SUPPORTED_LENGTH = 12;
1008
1113
  var AUTO_FOCUS_DELAY_MS = 250;
1114
+ var COMPLETE_PULSE_MS = 400;
1009
1115
  function OtpInput({
1010
1116
  value,
1011
1117
  onChange,
1012
1118
  maxLength,
1013
- disabled = false
1119
+ disabled = false,
1120
+ error = false
1014
1121
  }) {
1015
1122
  const inputRefs = react.useRef([]);
1123
+ const [completePulse, setCompletePulse] = react.useState(false);
1124
+ const prevLenRef = react.useRef(0);
1016
1125
  const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
1017
1126
  const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
1127
+ const isFull = value.length === safeMaxLength && /^\d+$/.test(value);
1018
1128
  react.useEffect(() => {
1019
1129
  if (disabled) return;
1020
1130
  const timer = window.setTimeout(() => {
@@ -1022,6 +1132,22 @@ function OtpInput({
1022
1132
  }, AUTO_FOCUS_DELAY_MS);
1023
1133
  return () => window.clearTimeout(timer);
1024
1134
  }, [disabled]);
1135
+ react.useEffect(() => {
1136
+ let t;
1137
+ if (isFull && prevLenRef.current < safeMaxLength) {
1138
+ setCompletePulse(true);
1139
+ t = window.setTimeout(
1140
+ () => setCompletePulse(false),
1141
+ COMPLETE_PULSE_MS
1142
+ );
1143
+ }
1144
+ prevLenRef.current = value.length;
1145
+ return () => {
1146
+ if (typeof t === "number") {
1147
+ window.clearTimeout(t);
1148
+ }
1149
+ };
1150
+ }, [isFull, value.length, safeMaxLength]);
1025
1151
  const focusInput = (index) => {
1026
1152
  if (index >= 0 && index < safeMaxLength) {
1027
1153
  inputRefs.current[index]?.focus();
@@ -1072,38 +1198,57 @@ function OtpInput({
1072
1198
  updateValue(newDigits);
1073
1199
  focusInput(Math.min(pasted.length, safeMaxLength - 1));
1074
1200
  };
1075
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2.5 justify-center", children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
1076
- "input",
1201
+ return /* @__PURE__ */ jsxRuntime.jsx(
1202
+ "div",
1077
1203
  {
1078
- ref: (el) => {
1079
- inputRefs.current[i] = el;
1080
- },
1081
- type: "text",
1082
- inputMode: "numeric",
1083
- maxLength: 1,
1084
- value: digit,
1085
- disabled,
1086
- onChange: (e) => handleChange(i, e.target.value.slice(-1)),
1087
- onKeyDown: (e) => handleKeyDown(i, e),
1088
- onPaste: handlePaste,
1089
- onFocus: (e) => e.target.select(),
1090
- "aria-label": `Digit ${i + 1}`,
1091
1204
  className: cn(
1092
- "w-12 h-14 text-center text-xl font-semibold rounded-xl",
1093
- "payman-otp-input otp-input",
1094
- "transition-all duration-150 cursor-text",
1095
- disabled && "cursor-not-allowed"
1096
- )
1097
- },
1098
- i
1099
- )) });
1205
+ "flex justify-center",
1206
+ error && "payman-otp-shake",
1207
+ completePulse && "payman-otp-complete-pulse"
1208
+ ),
1209
+ style: { gap: 10 },
1210
+ children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
1211
+ "input",
1212
+ {
1213
+ ref: (el) => {
1214
+ inputRefs.current[i] = el;
1215
+ },
1216
+ type: "text",
1217
+ inputMode: "numeric",
1218
+ maxLength: 1,
1219
+ value: digit,
1220
+ disabled,
1221
+ onChange: (e) => handleChange(i, e.target.value.slice(-1)),
1222
+ onKeyDown: (e) => handleKeyDown(i, e),
1223
+ onPaste: handlePaste,
1224
+ onFocus: (e) => e.target.select(),
1225
+ "aria-label": `Digit ${i + 1}`,
1226
+ className: cn(
1227
+ "text-center font-semibold rounded-lg",
1228
+ "payman-otp-input otp-input",
1229
+ "transition-all duration-150 cursor-text",
1230
+ disabled && "cursor-not-allowed",
1231
+ error && "payman-otp-input--error"
1232
+ ),
1233
+ style: {
1234
+ width: 44,
1235
+ height: 50,
1236
+ fontSize: 20
1237
+ }
1238
+ },
1239
+ i
1240
+ ))
1241
+ }
1242
+ );
1100
1243
  }
1101
1244
 
1102
1245
  // src/components/UserActionModal/constants.ts
1103
1246
  var BUTTON_LABELS = {
1104
- APPROVE: "Verify",
1105
- REJECT: "Reject",
1106
- RESEND: "Resend OTP"
1247
+ /** Link-style actions (new layout) */
1248
+ RESEND_CODE: "Resend OTP",
1249
+ CANCEL_TRANSFER: "Cancel Payment",
1250
+ /** Short cancel label for payee approval flows */
1251
+ CANCEL: "Cancel"
1107
1252
  };
1108
1253
  var RESEND_OTP_COOLDOWN_SECONDS = 30;
1109
1254
  var DEFAULT_OTP_MAX_LENGTH = 6;
@@ -1111,11 +1256,12 @@ var MIN_OTP_MAX_LENGTH = 1;
1111
1256
  var MAX_OTP_MAX_LENGTH = 12;
1112
1257
  var ACTION_PENDING_TIMEOUT_MS = 15e3;
1113
1258
  var MODAL_CONTENT = {
1114
- TITLE: "Verification Required",
1115
1259
  LOADING_APPROVE: "Verifying...",
1116
1260
  LOADING_REJECT: "Rejecting...",
1117
1261
  LOADING_RESEND: "Resending...",
1118
- RESEND_AVAILABLE_IN: "Resend OTP in"
1262
+ RESEND_AVAILABLE_IN: "Resend OTP in",
1263
+ SECURED_BY_PREFIX: "Secured by",
1264
+ SECURED_BY_BRAND: "Payman"
1119
1265
  };
1120
1266
 
1121
1267
  // src/components/UserActionModal/utils.ts
@@ -1132,6 +1278,18 @@ function getOtpSchemaFromRequest(schema) {
1132
1278
  maxLength: clampedMaxLength
1133
1279
  };
1134
1280
  }
1281
+ function formatAmountForDisplay(amount) {
1282
+ const normalized = amount.replace(/,/g, "").trim();
1283
+ const n = Number(normalized);
1284
+ if (!Number.isFinite(n)) {
1285
+ return amount.startsWith("$") ? amount : `$${amount}`;
1286
+ }
1287
+ return new Intl.NumberFormat("en-US", {
1288
+ style: "currency",
1289
+ currency: "USD"
1290
+ }).format(n);
1291
+ }
1292
+ var OTP_ERROR_FLASH_MS = 600;
1135
1293
  function UserActionModal({
1136
1294
  isOpen,
1137
1295
  userActionRequest,
@@ -1144,8 +1302,12 @@ function UserActionModal({
1144
1302
  const [actionType, setActionType] = react.useState(null);
1145
1303
  const [isSubmitting, setIsSubmitting] = react.useState(false);
1146
1304
  const [resendCooldownRemaining, setResendCooldownRemaining] = react.useState(0);
1305
+ const [otpError, setOtpError] = react.useState(false);
1147
1306
  const dialogRef = react.useRef(null);
1148
1307
  const previousFocusedRef = react.useRef(null);
1308
+ const lastAutoSubmittedRef = react.useRef("");
1309
+ const submitInFlightRef = react.useRef(false);
1310
+ const submitGenerationRef = react.useRef(0);
1149
1311
  const schema = getOtpSchemaFromRequest(userActionRequest?.requestedSchema);
1150
1312
  const resetActionState = react.useCallback(() => {
1151
1313
  setIsSubmitting(false);
@@ -1158,6 +1320,10 @@ function UserActionModal({
1158
1320
  setOtp("");
1159
1321
  resetActionState();
1160
1322
  setResendCooldownRemaining(0);
1323
+ setOtpError(false);
1324
+ lastAutoSubmittedRef.current = "";
1325
+ submitInFlightRef.current = false;
1326
+ submitGenerationRef.current += 1;
1161
1327
  }
1162
1328
  }, [isOpen, resetActionState]);
1163
1329
  react.useEffect(() => {
@@ -1170,8 +1336,13 @@ function UserActionModal({
1170
1336
  }, [resendCooldownRemaining]);
1171
1337
  react.useEffect(() => {
1172
1338
  if (clearOtpTrigger > 0) {
1173
- setOtp("");
1174
- resetActionState();
1339
+ setOtpError(true);
1340
+ const t = setTimeout(() => {
1341
+ setOtpError(false);
1342
+ setOtp("");
1343
+ resetActionState();
1344
+ }, OTP_ERROR_FLASH_MS);
1345
+ return () => clearTimeout(t);
1175
1346
  }
1176
1347
  }, [clearOtpTrigger, resetActionState]);
1177
1348
  react.useEffect(() => {
@@ -1180,6 +1351,39 @@ function UserActionModal({
1180
1351
  const timeout = setTimeout(resetActionState, ACTION_PENDING_TIMEOUT_MS);
1181
1352
  return () => clearTimeout(timeout);
1182
1353
  }, [isOpen, isSubmitting, actionType, resetActionState]);
1354
+ react.useEffect(() => {
1355
+ if (!isOpen || !userActionRequest) return;
1356
+ if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) {
1357
+ return;
1358
+ }
1359
+ if (isSubmitting || submitInFlightRef.current) return;
1360
+ if (lastAutoSubmittedRef.current === otp) return;
1361
+ lastAutoSubmittedRef.current = otp;
1362
+ submitInFlightRef.current = true;
1363
+ const submitGeneration = submitGenerationRef.current;
1364
+ void (async () => {
1365
+ setIsSubmitting(true);
1366
+ setActionType("approve");
1367
+ try {
1368
+ await onApprove(otp);
1369
+ } catch {
1370
+ if (submitGenerationRef.current !== submitGeneration) return;
1371
+ resetActionState();
1372
+ lastAutoSubmittedRef.current = otp;
1373
+ } finally {
1374
+ if (submitGenerationRef.current !== submitGeneration) return;
1375
+ submitInFlightRef.current = false;
1376
+ }
1377
+ })();
1378
+ }, [
1379
+ otp,
1380
+ isOpen,
1381
+ isSubmitting,
1382
+ userActionRequest,
1383
+ schema.maxLength,
1384
+ onApprove,
1385
+ resetActionState
1386
+ ]);
1183
1387
  react.useEffect(() => {
1184
1388
  if (!isOpen) return;
1185
1389
  const dialog = dialogRef.current;
@@ -1229,16 +1433,6 @@ function UserActionModal({
1229
1433
  previousFocusedRef.current?.focus();
1230
1434
  };
1231
1435
  }, [isOpen]);
1232
- const handleApprove = react.useCallback(async () => {
1233
- if (otp.length !== schema.maxLength || !/^\d+$/.test(otp)) return;
1234
- setIsSubmitting(true);
1235
- setActionType("approve");
1236
- try {
1237
- await onApprove(otp);
1238
- } catch {
1239
- resetActionState();
1240
- }
1241
- }, [otp, schema.maxLength, onApprove, resetActionState]);
1242
1436
  const handleReject = react.useCallback(async () => {
1243
1437
  setIsSubmitting(true);
1244
1438
  setActionType("reject");
@@ -1262,7 +1456,10 @@ function UserActionModal({
1262
1456
  }
1263
1457
  }, [resendCooldownRemaining, onResend]);
1264
1458
  if (!isOpen || !userActionRequest) return null;
1265
- const isOtpValid = otp.length === schema.maxLength && /^\d+$/.test(otp);
1459
+ const isPayment = userActionRequest.userActionType === "PAYMENT_APPROVAL" && Boolean(userActionRequest.metadata?.amount);
1460
+ const isPayee = userActionRequest.userActionType === "PAYEE_APPROVAL" && Boolean(userActionRequest.metadata?.payeeName);
1461
+ const isVerifying = actionType === "approve" && isSubmitting;
1462
+ const isCancelling = actionType === "reject" && isSubmitting;
1266
1463
  return /* @__PURE__ */ jsxRuntime.jsxs(
1267
1464
  "div",
1268
1465
  {
@@ -1294,7 +1491,7 @@ function UserActionModal({
1294
1491
  style: {
1295
1492
  flexShrink: 0,
1296
1493
  width: "100%",
1297
- maxWidth: 400,
1494
+ maxWidth: 440,
1298
1495
  minWidth: 0
1299
1496
  },
1300
1497
  children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1303,143 +1500,258 @@ function UserActionModal({
1303
1500
  ref: dialogRef,
1304
1501
  role: "dialog",
1305
1502
  "aria-modal": "true",
1306
- "aria-labelledby": "payman-modal-title",
1503
+ "aria-labelledby": "payman-user-action-message",
1307
1504
  className: cn(
1308
- "relative w-full rounded-2xl p-6 shadow-2xl",
1505
+ "relative w-full rounded-2xl shadow-2xl",
1309
1506
  "payman-modal-dialog payman-modal-animate"
1310
1507
  ),
1311
1508
  style: {
1312
1509
  width: "100%",
1313
- maxWidth: 400,
1510
+ maxWidth: 440,
1314
1511
  boxSizing: "border-box",
1512
+ padding: "36px 32px 28px",
1315
1513
  background: "var(--payman-modal-dialog-bg, var(--payman-card, #ffffff))",
1316
1514
  border: "1px solid var(--payman-modal-dialog-border, var(--payman-border, #e4e4e7))"
1317
1515
  },
1318
1516
  tabIndex: -1,
1319
1517
  children: [
1320
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center mb-5", children: [
1321
- /* @__PURE__ */ jsxRuntime.jsx(
1322
- "div",
1323
- {
1324
- className: "inline-flex items-center justify-center w-12 h-12 rounded-2xl payman-modal-icon-wrap mb-3",
1325
- style: {
1326
- background: "var(--payman-modal-icon-bg, color-mix(in srgb, var(--payman-primary, #18181b) 10%, transparent))",
1327
- border: "1px solid var(--payman-modal-icon-border, color-mix(in srgb, var(--payman-primary, #18181b) 20%, transparent))"
1328
- },
1329
- children: /* @__PURE__ */ jsxRuntime.jsx(
1330
- lucideReact.ShieldCheck,
1331
- {
1332
- className: "w-6 h-6 payman-modal-icon",
1333
- style: {
1334
- color: "var(--payman-modal-icon-fg, var(--payman-primary, #18181b))"
1335
- }
1336
- }
1337
- )
1338
- }
1339
- ),
1340
- /* @__PURE__ */ jsxRuntime.jsx(
1341
- "h2",
1342
- {
1343
- id: "payman-modal-title",
1344
- className: "text-lg font-semibold payman-modal-title tracking-tight",
1345
- style: {
1346
- color: "var(--payman-modal-title-fg, var(--payman-foreground, #18181b))"
1347
- },
1348
- children: MODAL_CONTENT.TITLE
1349
- }
1350
- )
1351
- ] }),
1518
+ /* @__PURE__ */ jsxRuntime.jsx(
1519
+ "button",
1520
+ {
1521
+ type: "button",
1522
+ onClick: handleReject,
1523
+ disabled: isSubmitting,
1524
+ className: "payman-modal-close-btn absolute flex items-center justify-center rounded-full border-0 bg-transparent p-0 cursor-pointer disabled:cursor-not-allowed",
1525
+ style: {
1526
+ top: 12,
1527
+ right: 12,
1528
+ width: 28,
1529
+ height: 28
1530
+ },
1531
+ "aria-label": "Close",
1532
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16, strokeWidth: 2.5 })
1533
+ }
1534
+ ),
1352
1535
  /* @__PURE__ */ jsxRuntime.jsx(
1353
1536
  "p",
1354
1537
  {
1355
- className: "text-sm payman-modal-desc text-center mb-6 leading-relaxed px-0.5",
1538
+ id: "payman-user-action-message",
1539
+ className: "text-center leading-snug",
1356
1540
  style: {
1541
+ fontSize: 14,
1542
+ lineHeight: 1.5,
1543
+ margin: "0 0 20px",
1544
+ paddingRight: 24,
1545
+ paddingLeft: 24,
1357
1546
  color: "var(--payman-modal-desc-fg, var(--payman-muted-foreground, #71717a))"
1358
1547
  },
1359
1548
  children: userActionRequest.message
1360
1549
  }
1361
1550
  ),
1362
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsxRuntime.jsx(
1363
- OtpInput,
1551
+ isPayment && /* @__PURE__ */ jsxRuntime.jsx(
1552
+ "p",
1364
1553
  {
1365
- value: otp,
1366
- onChange: setOtp,
1367
- maxLength: schema.maxLength,
1368
- disabled: isSubmitting
1554
+ className: "text-center font-semibold uppercase",
1555
+ style: {
1556
+ fontSize: 12,
1557
+ letterSpacing: "0.08em",
1558
+ margin: "0 0 4px",
1559
+ color: "var(--payman-modal-desc-fg, var(--payman-muted-foreground, #71717a))",
1560
+ opacity: 0.7
1561
+ },
1562
+ children: "Pay"
1369
1563
  }
1370
- ) }),
1371
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
1372
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2.5", children: [
1373
- /* @__PURE__ */ jsxRuntime.jsxs(
1374
- "button",
1375
- {
1376
- type: "button",
1377
- onClick: handleReject,
1378
- disabled: isSubmitting,
1379
- className: cn(
1380
- "flex-1 flex items-center justify-center gap-2",
1381
- "min-h-[48px] py-3 px-4 rounded-xl text-sm font-medium border-0 cursor-pointer",
1382
- "payman-modal-btn-reject",
1383
- "active:scale-[0.98] transition-all duration-150",
1384
- "disabled:cursor-not-allowed"
1385
- ),
1386
- style: {
1387
- background: "var(--payman-modal-btn-reject-bg, color-mix(in srgb, var(--payman-destructive, #ef4444) 10%, transparent))",
1388
- color: "var(--payman-modal-btn-reject-fg, var(--payman-destructive, #ef4444))"
1389
- },
1390
- children: [
1391
- actionType === "reject" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 animate-spin shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4 shrink-0", strokeWidth: 2.5 }),
1392
- actionType === "reject" ? MODAL_CONTENT.LOADING_REJECT : BUTTON_LABELS.REJECT
1393
- ]
1394
- }
1395
- ),
1396
- /* @__PURE__ */ jsxRuntime.jsxs(
1397
- "button",
1398
- {
1399
- type: "button",
1400
- onClick: handleApprove,
1401
- disabled: !isOtpValid || isSubmitting,
1402
- className: cn(
1403
- "flex-1 flex items-center justify-center gap-2",
1404
- "min-h-[48px] py-3 px-4 rounded-xl text-sm font-medium border-0 cursor-pointer",
1405
- "payman-modal-btn-approve",
1406
- "active:scale-[0.98] transition-all duration-150",
1407
- "disabled:cursor-not-allowed"
1408
- ),
1409
- style: {
1410
- background: "var(--payman-modal-btn-approve-bg, var(--payman-primary, #18181b))",
1411
- color: "var(--payman-modal-btn-approve-fg, var(--payman-primary-foreground, #fafafa))"
1412
- },
1413
- children: [
1414
- actionType === "approve" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 animate-spin shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-4 h-4 shrink-0", strokeWidth: 2.5 }),
1415
- actionType === "approve" ? MODAL_CONTENT.LOADING_APPROVE : BUTTON_LABELS.APPROVE
1416
- ]
1417
- }
1418
- )
1419
- ] }),
1420
- /* @__PURE__ */ jsxRuntime.jsxs(
1421
- "button",
1422
- {
1423
- type: "button",
1424
- onClick: handleResend,
1425
- disabled: isSubmitting || resendCooldownRemaining > 0,
1426
- className: cn(
1427
- "w-full flex items-center justify-center gap-2",
1428
- "min-h-[48px] py-3 px-4 rounded-xl text-sm font-medium cursor-pointer",
1429
- "payman-modal-btn-resend",
1430
- "transition-all duration-150 disabled:cursor-not-allowed"
1564
+ ),
1565
+ isPayment && userActionRequest.metadata?.amount && /* @__PURE__ */ jsxRuntime.jsx(
1566
+ "p",
1567
+ {
1568
+ className: "text-center font-bold tabular-nums tracking-tight",
1569
+ style: {
1570
+ fontSize: 42,
1571
+ lineHeight: 1.1,
1572
+ margin: "0 0 32px",
1573
+ color: "var(--payman-modal-hero-fg, #0a3b44)"
1574
+ },
1575
+ children: formatAmountForDisplay(userActionRequest.metadata.amount)
1576
+ }
1577
+ ),
1578
+ isPayee && /* @__PURE__ */ jsxRuntime.jsx(
1579
+ "p",
1580
+ {
1581
+ className: "text-center font-semibold uppercase",
1582
+ style: {
1583
+ fontSize: 12,
1584
+ letterSpacing: "0.08em",
1585
+ margin: "0 0 4px",
1586
+ color: "var(--payman-modal-desc-fg, var(--payman-muted-foreground, #71717a))",
1587
+ opacity: 0.7
1588
+ },
1589
+ children: "Create Payee"
1590
+ }
1591
+ ),
1592
+ isPayee && userActionRequest.metadata?.payeeName && /* @__PURE__ */ jsxRuntime.jsxs(
1593
+ "div",
1594
+ {
1595
+ className: "text-center",
1596
+ style: { margin: "0 0 32px" },
1597
+ children: [
1598
+ /* @__PURE__ */ jsxRuntime.jsx(
1599
+ "p",
1600
+ {
1601
+ className: "font-bold leading-tight",
1602
+ style: {
1603
+ fontSize: 28,
1604
+ margin: "0 0 4px",
1605
+ color: "var(--payman-modal-hero-fg, #0a3b44)"
1606
+ },
1607
+ children: userActionRequest.metadata.payeeName
1608
+ }
1431
1609
  ),
1610
+ userActionRequest.metadata.payeeType ? /* @__PURE__ */ jsxRuntime.jsx(
1611
+ "p",
1612
+ {
1613
+ className: "font-semibold uppercase",
1614
+ style: {
1615
+ fontSize: 10,
1616
+ letterSpacing: "0.08em",
1617
+ margin: 0,
1618
+ color: "var(--payman-modal-hero-fg, #0a3b44)",
1619
+ opacity: 0.85
1620
+ },
1621
+ children: userActionRequest.metadata.payeeType
1622
+ }
1623
+ ) : null
1624
+ ]
1625
+ }
1626
+ ),
1627
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 30 }, children: [
1628
+ /* @__PURE__ */ jsxRuntime.jsx(
1629
+ OtpInput,
1630
+ {
1631
+ value: otp,
1632
+ onChange: setOtp,
1633
+ maxLength: schema.maxLength,
1634
+ disabled: isSubmitting,
1635
+ error: otpError
1636
+ }
1637
+ ),
1638
+ isVerifying ? /* @__PURE__ */ jsxRuntime.jsxs(
1639
+ "div",
1640
+ {
1641
+ className: "flex items-center justify-center gap-2",
1432
1642
  style: {
1433
- border: "1px solid var(--payman-modal-btn-resend-border, var(--payman-border, #e4e4e7))",
1434
- color: "var(--payman-modal-btn-resend-fg, var(--payman-muted-foreground, #71717a))"
1643
+ marginTop: 10,
1644
+ fontSize: 12,
1645
+ color: "var(--payman-modal-hero-fg, #0a3b44)"
1435
1646
  },
1436
1647
  children: [
1437
- actionType === "resend" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-4 h-4 animate-spin shrink-0" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "w-4 h-4 shrink-0", strokeWidth: 2.5 }),
1438
- actionType === "resend" ? MODAL_CONTENT.LOADING_RESEND : resendCooldownRemaining > 0 ? `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s` : BUTTON_LABELS.RESEND
1648
+ /* @__PURE__ */ jsxRuntime.jsx(
1649
+ lucideReact.Loader2,
1650
+ {
1651
+ className: "animate-spin shrink-0",
1652
+ style: { width: 14, height: 14 }
1653
+ }
1654
+ ),
1655
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: MODAL_CONTENT.LOADING_APPROVE })
1439
1656
  ]
1440
1657
  }
1441
- )
1442
- ] })
1658
+ ) : null
1659
+ ] }),
1660
+ /* @__PURE__ */ jsxRuntime.jsxs(
1661
+ "div",
1662
+ {
1663
+ className: "flex flex-col items-center",
1664
+ style: { gap: 12, marginBottom: 32 },
1665
+ children: [
1666
+ /* @__PURE__ */ jsxRuntime.jsx(
1667
+ "button",
1668
+ {
1669
+ type: "button",
1670
+ onClick: handleResend,
1671
+ disabled: isSubmitting || resendCooldownRemaining > 0,
1672
+ className: "payman-modal-link-resend border-0 bg-transparent p-0 cursor-pointer font-semibold transition-colors disabled:cursor-not-allowed disabled:opacity-40",
1673
+ style: {
1674
+ fontSize: 11,
1675
+ letterSpacing: "0.06em",
1676
+ color: "var(--payman-modal-desc-fg, var(--payman-muted-foreground, #71717a))"
1677
+ },
1678
+ children: actionType === "resend" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
1679
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 animate-spin" }),
1680
+ MODAL_CONTENT.LOADING_RESEND
1681
+ ] }) : resendCooldownRemaining > 0 ? `${MODAL_CONTENT.RESEND_AVAILABLE_IN} ${resendCooldownRemaining}s` : BUTTON_LABELS.RESEND_CODE
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ jsxRuntime.jsx(
1685
+ "button",
1686
+ {
1687
+ type: "button",
1688
+ onClick: handleReject,
1689
+ disabled: isSubmitting,
1690
+ className: "payman-modal-link-cancel border-0 bg-transparent p-0 cursor-pointer font-semibold transition-colors disabled:cursor-not-allowed disabled:opacity-40",
1691
+ style: {
1692
+ fontSize: 11,
1693
+ letterSpacing: "0.06em",
1694
+ color: "var(--payman-modal-desc-fg, var(--payman-muted-foreground, #71717a))"
1695
+ },
1696
+ children: isCancelling ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
1697
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 animate-spin" }),
1698
+ MODAL_CONTENT.LOADING_REJECT
1699
+ ] }) : isPayee ? BUTTON_LABELS.CANCEL : BUTTON_LABELS.CANCEL_TRANSFER
1700
+ }
1701
+ )
1702
+ ]
1703
+ }
1704
+ ),
1705
+ /* @__PURE__ */ jsxRuntime.jsxs(
1706
+ "div",
1707
+ {
1708
+ className: "flex flex-row flex-nowrap items-center justify-center gap-1.5",
1709
+ style: {
1710
+ borderTop: "1px solid var(--payman-modal-dialog-border, var(--payman-border, #e4e4e7))",
1711
+ paddingTop: 20
1712
+ },
1713
+ children: [
1714
+ /* @__PURE__ */ jsxRuntime.jsx(
1715
+ "span",
1716
+ {
1717
+ className: "font-medium whitespace-nowrap",
1718
+ style: {
1719
+ fontSize: 11,
1720
+ color: "var(--payman-modal-desc-fg, var(--payman-muted-foreground, #71717a))",
1721
+ opacity: 0.9
1722
+ },
1723
+ children: MODAL_CONTENT.SECURED_BY_PREFIX
1724
+ }
1725
+ ),
1726
+ /* @__PURE__ */ jsxRuntime.jsx(
1727
+ "img",
1728
+ {
1729
+ src: payman_mono_crop_blue_default,
1730
+ alt: "",
1731
+ style: {
1732
+ height: 18,
1733
+ width: "auto",
1734
+ flexShrink: 0,
1735
+ objectFit: "contain"
1736
+ },
1737
+ draggable: false
1738
+ }
1739
+ ),
1740
+ /* @__PURE__ */ jsxRuntime.jsx(
1741
+ "span",
1742
+ {
1743
+ className: "font-bold whitespace-nowrap",
1744
+ style: {
1745
+ fontSize: 12,
1746
+ letterSpacing: "0.02em",
1747
+ color: "var(--payman-modal-brand-fg, #0a3b44)"
1748
+ },
1749
+ children: MODAL_CONTENT.SECURED_BY_BRAND
1750
+ }
1751
+ )
1752
+ ]
1753
+ }
1754
+ )
1443
1755
  ]
1444
1756
  }
1445
1757
  )
@@ -1467,6 +1779,7 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1467
1779
  }, ref) {
1468
1780
  const [inputValue, setInputValue] = react.useState("");
1469
1781
  const prevInputValueRef = react.useRef(inputValue);
1782
+ const [hasEverSentMessage, setHasEverSentMessage] = react.useState(false);
1470
1783
  const chat = paymanTypescriptAskSdk.useChat(config, callbacks);
1471
1784
  const {
1472
1785
  messages,
@@ -1479,6 +1792,11 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1479
1792
  getSessionId,
1480
1793
  getMessages
1481
1794
  } = chat;
1795
+ react.useEffect(() => {
1796
+ if (messages.length > 0 && !hasEverSentMessage) {
1797
+ setHasEverSentMessage(true);
1798
+ }
1799
+ }, [messages.length, hasEverSentMessage]);
1482
1800
  const userActionState = chat.userActionState ?? DEFAULT_USER_ACTION_STATE;
1483
1801
  const approveUserAction = chat.approveUserAction ?? NOOP_ASYNC;
1484
1802
  const rejectUserAction = chat.rejectUserAction ?? NOOP_ASYNC;
@@ -1527,14 +1845,17 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1527
1845
  isWaitingForResponse
1528
1846
  ]
1529
1847
  );
1848
+ const { onExecutionTraceClick, onResetSession } = callbacks;
1530
1849
  react.useImperativeHandle(ref, () => ({
1531
- resetSession,
1850
+ resetSession: () => {
1851
+ resetSession();
1852
+ onResetSession?.();
1853
+ },
1532
1854
  clearMessages,
1533
1855
  cancelStream,
1534
1856
  getSessionId,
1535
1857
  getMessages
1536
- }), [resetSession, clearMessages, cancelStream, getSessionId, getMessages]);
1537
- const { onExecutionTraceClick } = callbacks;
1858
+ }), [resetSession, clearMessages, cancelStream, getSessionId, getMessages, onResetSession]);
1538
1859
  const {
1539
1860
  placeholder = "Type your message...",
1540
1861
  emptyStateText = "What can I help with?",
@@ -1556,7 +1877,9 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1556
1877
  animated = true,
1557
1878
  isChatDisabled = false,
1558
1879
  disabledComponent,
1559
- showEmptyStateIcon = true
1880
+ showEmptyStateIcon = true,
1881
+ emptyStateComponent,
1882
+ showResetSession = false
1560
1883
  } = config;
1561
1884
  const isSessionParamsConfigured = react.useMemo(() => {
1562
1885
  if (!sessionParams) return false;
@@ -1564,9 +1887,9 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1564
1887
  }, [sessionParams?.id, sessionParams?.name]);
1565
1888
  react.useEffect(() => {
1566
1889
  const wasEmpty = prevInputValueRef.current.trim() === "";
1567
- const isEmpty = inputValue.trim() === "";
1890
+ const isEmpty2 = inputValue.trim() === "";
1568
1891
  prevInputValueRef.current = inputValue;
1569
- if (!wasEmpty && isEmpty) {
1892
+ if (!wasEmpty && isEmpty2) {
1570
1893
  clearTranscript();
1571
1894
  if (isRecording) {
1572
1895
  stopRecording();
@@ -1582,14 +1905,23 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1582
1905
  setInputValue("");
1583
1906
  }
1584
1907
  };
1908
+ const handleCancelRecording = () => {
1909
+ stopRecording();
1910
+ clearTranscript();
1911
+ setInputValue("");
1912
+ };
1913
+ const handleConfirmRecording = () => {
1914
+ stopRecording();
1915
+ };
1585
1916
  const isInputDisabled = isWaitingForResponse || !isSessionParamsConfigured || disableInput;
1917
+ const isEmpty = messages.length === 0;
1586
1918
  if (isChatDisabled) {
1587
1919
  if (disabledComponent) {
1588
1920
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
1589
1921
  "div",
1590
1922
  {
1591
1923
  className: cn(
1592
- "bg-card overflow-hidden flex flex-col flex-[4]",
1924
+ "bg-background overflow-hidden flex flex-col flex-[4]",
1593
1925
  className
1594
1926
  ),
1595
1927
  style,
@@ -1604,7 +1936,7 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1604
1936
  "div",
1605
1937
  {
1606
1938
  className: cn(
1607
- "bg-card overflow-hidden flex flex-col flex-[4]",
1939
+ "bg-background overflow-hidden flex flex-col flex-[4]",
1608
1940
  className
1609
1941
  ),
1610
1942
  style,
@@ -1615,62 +1947,138 @@ var PaymanChat = react.forwardRef(function PaymanChat2({
1615
1947
  }
1616
1948
  ) });
1617
1949
  }
1950
+ const inputElement = hasAskPermission && /* @__PURE__ */ jsxRuntime.jsx(
1951
+ ChatInput,
1952
+ {
1953
+ value: inputValue,
1954
+ onChange: setInputValue,
1955
+ onSend: handleSend,
1956
+ onPause: cancelStream,
1957
+ disabled: isInputDisabled,
1958
+ placeholder: isRecording ? "Listening..." : placeholder,
1959
+ isWaitingForResponse,
1960
+ hasSelectedSession: true,
1961
+ isSessionParamsConfigured,
1962
+ enableVoice: config.enableVoice === true,
1963
+ onVoicePress: isRecording ? stopRecording : startRecording,
1964
+ voiceAvailable: config.enableVoice === true && voiceAvailable,
1965
+ isRecording,
1966
+ transcribedText: inputValue,
1967
+ onCancelRecording: handleCancelRecording,
1968
+ onConfirmRecording: handleConfirmRecording,
1969
+ inputStyle,
1970
+ layout,
1971
+ showResetSession,
1972
+ onResetSession: () => {
1973
+ resetSession();
1974
+ onResetSession?.();
1975
+ }
1976
+ }
1977
+ );
1618
1978
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
1619
1979
  "div",
1620
1980
  {
1621
1981
  className: cn(
1622
- "bg-card overflow-hidden flex flex-col flex-[4]",
1982
+ "bg-background overflow-hidden flex flex-col flex-[4]",
1623
1983
  className
1624
1984
  ),
1625
1985
  style,
1626
1986
  children: [
1627
1987
  children,
1628
- /* @__PURE__ */ jsxRuntime.jsx(
1629
- MessageList,
1630
- {
1631
- messages,
1632
- isLoading: false,
1633
- emptyStateText,
1634
- showEmptyStateIcon,
1635
- layout,
1636
- showTimestamps,
1637
- stage: config.stage || "DEV",
1638
- animated,
1639
- showAgentName,
1640
- agentName,
1641
- showAvatars,
1642
- showUserAvatar,
1643
- showAssistantAvatar,
1644
- showExecutionSteps,
1645
- showStreamingDot,
1646
- streamingStepsText,
1647
- completedStepsText,
1648
- onExecutionTraceClick,
1649
- onLoadMoreMessages,
1650
- isLoadingMoreMessages,
1651
- hasMoreMessages
1652
- }
1653
- ),
1654
- hasAskPermission && /* @__PURE__ */ jsxRuntime.jsx(
1655
- ChatInput,
1656
- {
1657
- value: inputValue,
1658
- onChange: setInputValue,
1659
- onSend: handleSend,
1660
- onPause: cancelStream,
1661
- disabled: isInputDisabled,
1662
- placeholder: isRecording ? "Listening..." : placeholder,
1663
- isWaitingForResponse,
1664
- hasSelectedSession: true,
1665
- isSessionParamsConfigured,
1666
- enableVoice: config.enableVoice === true,
1667
- onVoicePress: isRecording ? stopRecording : startRecording,
1668
- voiceAvailable: config.enableVoice === true && voiceAvailable,
1669
- isRecording,
1670
- inputStyle,
1671
- layout
1672
- }
1673
- ),
1988
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: isEmpty && !hasEverSentMessage ? (
1989
+ /* ---- Centered empty state with input ---- */
1990
+ /* @__PURE__ */ jsxRuntime.jsx(
1991
+ framerMotion.motion.div,
1992
+ {
1993
+ initial: { opacity: 1 },
1994
+ exit: { opacity: 0 },
1995
+ transition: { duration: 0.3 },
1996
+ className: "payman-empty-centered-layout",
1997
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-empty-centered-inner", children: [
1998
+ /* @__PURE__ */ jsxRuntime.jsx(
1999
+ MessageList,
2000
+ {
2001
+ messages,
2002
+ isLoading: false,
2003
+ emptyStateText,
2004
+ showEmptyStateIcon,
2005
+ emptyStateComponent,
2006
+ layout,
2007
+ showTimestamps,
2008
+ stage: config.stage || "DEV",
2009
+ animated,
2010
+ showAgentName,
2011
+ agentName,
2012
+ showAvatars,
2013
+ showUserAvatar,
2014
+ showAssistantAvatar,
2015
+ showExecutionSteps,
2016
+ showStreamingDot,
2017
+ streamingStepsText,
2018
+ completedStepsText,
2019
+ onExecutionTraceClick,
2020
+ onLoadMoreMessages,
2021
+ isLoadingMoreMessages,
2022
+ hasMoreMessages
2023
+ }
2024
+ ),
2025
+ /* @__PURE__ */ jsxRuntime.jsx(
2026
+ framerMotion.motion.div,
2027
+ {
2028
+ initial: { opacity: 0, y: 12 },
2029
+ animate: { opacity: 1, y: 0 },
2030
+ transition: { delay: 0.2, duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] },
2031
+ className: "payman-empty-centered-input",
2032
+ children: inputElement
2033
+ }
2034
+ )
2035
+ ] })
2036
+ },
2037
+ "empty-centered"
2038
+ )
2039
+ ) : (
2040
+ /* ---- Normal chat layout ---- */
2041
+ /* @__PURE__ */ jsxRuntime.jsxs(
2042
+ framerMotion.motion.div,
2043
+ {
2044
+ initial: hasEverSentMessage ? { opacity: 0 } : false,
2045
+ animate: { opacity: 1 },
2046
+ transition: { duration: 0.3 },
2047
+ className: "flex flex-col flex-1 min-h-0",
2048
+ children: [
2049
+ /* @__PURE__ */ jsxRuntime.jsx(
2050
+ MessageList,
2051
+ {
2052
+ messages,
2053
+ isLoading: false,
2054
+ emptyStateText,
2055
+ showEmptyStateIcon,
2056
+ emptyStateComponent,
2057
+ layout,
2058
+ showTimestamps,
2059
+ stage: config.stage || "DEV",
2060
+ animated,
2061
+ showAgentName,
2062
+ agentName,
2063
+ showAvatars,
2064
+ showUserAvatar,
2065
+ showAssistantAvatar,
2066
+ showExecutionSteps,
2067
+ showStreamingDot,
2068
+ streamingStepsText,
2069
+ completedStepsText,
2070
+ onExecutionTraceClick,
2071
+ onLoadMoreMessages,
2072
+ isLoadingMoreMessages,
2073
+ hasMoreMessages
2074
+ }
2075
+ ),
2076
+ inputElement
2077
+ ]
2078
+ },
2079
+ "chat-layout"
2080
+ )
2081
+ ) }),
1674
2082
  /* @__PURE__ */ jsxRuntime.jsx(
1675
2083
  UserActionModal,
1676
2084
  {