smartcomply-web-sdk 1.0.48 → 1.0.50

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 (33) hide show
  1. package/dist/client/HttpClient.d.ts +6 -1
  2. package/dist/client/HttpClient.d.ts.map +1 -1
  3. package/dist/client/HttpClient.js +11 -2
  4. package/dist/client/HttpClient.js.map +1 -1
  5. package/dist/esm/client/HttpClient.d.ts +6 -1
  6. package/dist/esm/client/HttpClient.d.ts.map +1 -1
  7. package/dist/esm/client/HttpClient.js +11 -2
  8. package/dist/esm/client/HttpClient.js.map +1 -1
  9. package/dist/esm/flow/SmartComplyFlow.d.ts.map +1 -1
  10. package/dist/esm/flow/SmartComplyFlow.js +6 -8
  11. package/dist/esm/flow/SmartComplyFlow.js.map +1 -1
  12. package/dist/esm/modules/liveness/LivenessUI.d.ts +2 -0
  13. package/dist/esm/modules/liveness/LivenessUI.d.ts.map +1 -1
  14. package/dist/esm/modules/liveness/LivenessUI.js +26 -6
  15. package/dist/esm/modules/liveness/LivenessUI.js.map +1 -1
  16. package/dist/esm/modules/liveness/liveness.d.ts +12 -1
  17. package/dist/esm/modules/liveness/liveness.d.ts.map +1 -1
  18. package/dist/esm/modules/liveness/liveness.js +16 -10
  19. package/dist/esm/modules/liveness/liveness.js.map +1 -1
  20. package/dist/flow/SmartComplyFlow.d.ts.map +1 -1
  21. package/dist/flow/SmartComplyFlow.js +6 -8
  22. package/dist/flow/SmartComplyFlow.js.map +1 -1
  23. package/dist/modules/liveness/LivenessUI.d.ts +2 -0
  24. package/dist/modules/liveness/LivenessUI.d.ts.map +1 -1
  25. package/dist/modules/liveness/LivenessUI.js +26 -6
  26. package/dist/modules/liveness/LivenessUI.js.map +1 -1
  27. package/dist/modules/liveness/liveness.d.ts +12 -1
  28. package/dist/modules/liveness/liveness.d.ts.map +1 -1
  29. package/dist/modules/liveness/liveness.js +16 -10
  30. package/dist/modules/liveness/liveness.js.map +1 -1
  31. package/dist/smartcomply.browser.js +143 -116
  32. package/dist/smartcomply.browser.js.map +2 -2
  33. package/package.json +2 -2
@@ -126,12 +126,21 @@ var SmartComplySDK = (() => {
126
126
  });
127
127
  }
128
128
  /**
129
- * Unauthenticated GET — used for public endpoints (e.g. status polling after session revoke).
129
+ * GET for endpoints that work without auth (status polling still works after
130
+ * session revoke) but return additional fields when a live session token is
131
+ * presented — e.g. sdk-result/ only includes OCR/PII fields for the session
132
+ * that owns the entry. Attaches the token opportunistically when we still
133
+ * have one; the backend falls back to the public (non-PII) response if it's
134
+ * missing, invalid, or already revoked.
130
135
  */
131
136
  async publicGet(path) {
137
+ const headers = { "Content-Type": "application/json" };
138
+ if (this.sessionToken) {
139
+ headers["x-access-token"] = this.sessionToken;
140
+ }
132
141
  return this._fetch(path, {
133
142
  method: "GET",
134
- headers: { "Content-Type": "application/json" }
143
+ headers
135
144
  });
136
145
  }
137
146
  /**
@@ -3626,7 +3635,7 @@ var SmartComplySDK = (() => {
3626
3635
  Pn(s2, 1, (i2.left + i2.right) / 2), Pn(s2, 2, (i2.top + i2.bottom) / 2), Pn(s2, 4, i2.right - i2.left), Pn(s2, 3, i2.bottom - i2.top);
3627
3636
  } else Pn(s2, 1, 0.5), Pn(s2, 2, 0.5), Pn(s2, 4, 1), Pn(s2, 3, 1);
3628
3637
  if (n2?.rotationDegrees) {
3629
- if (n2?.rotationDegrees % 90 != 0) throw Error("Expected rotation to be a multiple of 90\xB0.");
3638
+ if (n2?.rotationDegrees % 90 != 0) throw Error("Expected rotation to be a multiple of 90°.");
3630
3639
  if (Pn(s2, 5, -Math.PI * n2.rotationDegrees / 180), n2?.rotationDegrees % 180 != 0) {
3631
3640
  const [t3, r3] = sa(e2);
3632
3641
  n2 = Fn(s2, 3) * r3 / t3, i2 = Fn(s2, 4) * t3 / r3, Pn(s2, 4, n2), Pn(s2, 3, i2);
@@ -4555,22 +4564,22 @@ var SmartComplySDK = (() => {
4555
4564
 
4556
4565
  // src/modules/liveness/LivenessUI.ts
4557
4566
  var ICONS = {
4558
- BLINK: "\u{1F441}",
4559
- TURN_LEFT: "\u2194",
4560
- TURN_RIGHT: "\u2194",
4561
- TURN_HEAD: "\u2194",
4562
- OPEN_MOUTH: "\u{1F62E}"
4567
+ BLINK: "👁",
4568
+ TURN_LEFT: "↔",
4569
+ TURN_RIGHT: "↔",
4570
+ TURN_HEAD: "↔",
4571
+ OPEN_MOUTH: "😮"
4563
4572
  };
4564
4573
  var ACTION_CUES = {
4565
- BLINK: `<div style="font-size:52px;line-height:1;animation:sc-blink 1.2s ease-in-out infinite;">\u{1F441}\uFE0F</div>
4574
+ BLINK: `<div style="font-size:52px;line-height:1;animation:sc-blink 1.2s ease-in-out infinite;">👁️</div>
4566
4575
  <div style="font-size:12px;font-weight:600;color:#fff;margin-top:6px;letter-spacing:0.5px;">BLINK YOUR EYES</div>`,
4567
- TURN_LEFT: `<div style="font-size:52px;line-height:1;animation:sc-turn-head 1.4s ease-in-out infinite;">\u2194\uFE0F</div>
4576
+ TURN_LEFT: `<div style="font-size:52px;line-height:1;animation:sc-turn-head 1.4s ease-in-out infinite;">↔️</div>
4568
4577
  <div style="font-size:12px;font-weight:600;color:#fff;margin-top:6px;letter-spacing:0.5px;">TURN HEAD SIDEWAYS</div>`,
4569
- TURN_RIGHT: `<div style="font-size:52px;line-height:1;animation:sc-turn-head 1.4s ease-in-out infinite;">\u2194\uFE0F</div>
4578
+ TURN_RIGHT: `<div style="font-size:52px;line-height:1;animation:sc-turn-head 1.4s ease-in-out infinite;">↔️</div>
4570
4579
  <div style="font-size:12px;font-weight:600;color:#fff;margin-top:6px;letter-spacing:0.5px;">TURN HEAD SIDEWAYS</div>`,
4571
- TURN_HEAD: `<div style="font-size:52px;line-height:1;animation:sc-turn-head 1.4s ease-in-out infinite;">\u2194\uFE0F</div>
4580
+ TURN_HEAD: `<div style="font-size:52px;line-height:1;animation:sc-turn-head 1.4s ease-in-out infinite;">↔️</div>
4572
4581
  <div style="font-size:12px;font-weight:600;color:#fff;margin-top:6px;letter-spacing:0.5px;">TURN HEAD SIDE TO SIDE</div>`,
4573
- OPEN_MOUTH: `<div style="font-size:52px;line-height:1;animation:sc-mouth 1.2s ease-in-out infinite;">\u{1F62E}</div>
4582
+ OPEN_MOUTH: `<div style="font-size:52px;line-height:1;animation:sc-mouth 1.2s ease-in-out infinite;">😮</div>
4574
4583
  <div style="font-size:12px;font-weight:600;color:#fff;margin-top:6px;letter-spacing:0.5px;">OPEN YOUR MOUTH</div>`
4575
4584
  };
4576
4585
  function injectLivenessKeyframes() {
@@ -4616,6 +4625,13 @@ var SmartComplySDK = (() => {
4616
4625
  this.totalActions = 0;
4617
4626
  this.currentCueAction = null;
4618
4627
  this.docCaptureRoot = null;
4628
+ // updateActions() is called on every requestAnimationFrame tick (~60fps,
4629
+ // up to the challenge's ~45s time limit) — cache each action's step
4630
+ // element (avoids a querySelector per action per frame) and its last
4631
+ // rendered detected/active combination (avoids rewriting the same style
4632
+ // properties every frame when nothing about that action changed).
4633
+ this.stepEls = null;
4634
+ this.lastActionRender = /* @__PURE__ */ new Map();
4619
4635
  }
4620
4636
  mount(container, challenge) {
4621
4637
  injectLivenessKeyframes();
@@ -4732,6 +4748,8 @@ var SmartComplySDK = (() => {
4732
4748
  progressWrap.appendChild(this.progressBarEl);
4733
4749
  this.stepsEl = document.createElement("div");
4734
4750
  this.stepsEl.style.cssText = "display:flex;flex-direction:column;gap:6px;flex:1;";
4751
+ this.stepEls = /* @__PURE__ */ new Map();
4752
+ this.lastActionRender = /* @__PURE__ */ new Map();
4735
4753
  for (let i2 = 0; i2 < challenge.actions.length; i2++) {
4736
4754
  const action = challenge.actions[i2];
4737
4755
  const step = document.createElement("div");
@@ -4765,6 +4783,7 @@ var SmartComplySDK = (() => {
4765
4783
  step.appendChild(label);
4766
4784
  step.appendChild(icon);
4767
4785
  this.stepsEl.appendChild(step);
4786
+ this.stepEls.set(action, { step, num });
4768
4787
  }
4769
4788
  stepsCol.appendChild(progressWrap);
4770
4789
  stepsCol.appendChild(this.stepsEl);
@@ -4782,24 +4801,24 @@ var SmartComplySDK = (() => {
4782
4801
  return this.videoEl;
4783
4802
  }
4784
4803
  updateActions(states) {
4785
- if (!this.stepsEl || !this.progressBarEl) return;
4804
+ if (!this.stepsEl || !this.progressBarEl || !this.stepEls) return;
4786
4805
  let completed = 0;
4787
- const activeState = states.find((s2) => s2.active && !s2.detected) ?? null;
4788
4806
  for (const state of states) {
4789
- const step = this.stepsEl.querySelector(
4790
- `[data-action="${state.action}"]`
4791
- );
4792
- if (!step) continue;
4793
- const num = step.querySelector(".sc-step-num");
4807
+ if (state.detected) completed++;
4808
+ const renderKey = state.detected ? "detected" : state.active ? "active" : "idle";
4809
+ if (this.lastActionRender.get(state.action) === renderKey) continue;
4810
+ this.lastActionRender.set(state.action, renderKey);
4811
+ const cached = this.stepEls.get(state.action);
4812
+ if (!cached) continue;
4813
+ const { step, num } = cached;
4794
4814
  if (state.detected) {
4795
- completed++;
4796
4815
  step.style.opacity = "1";
4797
4816
  step.style.background = "rgba(34,197,94,0.12)";
4798
4817
  step.style.borderColor = "rgba(34,197,94,0.3)";
4799
4818
  if (num) {
4800
4819
  num.style.background = "#22c55e";
4801
4820
  num.style.borderColor = "#22c55e";
4802
- num.textContent = "\u2713";
4821
+ num.textContent = "✓";
4803
4822
  }
4804
4823
  } else if (state.active) {
4805
4824
  step.style.opacity = "1";
@@ -4811,6 +4830,7 @@ var SmartComplySDK = (() => {
4811
4830
  }
4812
4831
  }
4813
4832
  }
4833
+ const activeState = states.find((s2) => s2.active && !s2.detected) ?? null;
4814
4834
  const pct = this.totalActions > 0 ? completed / this.totalActions * 100 : 0;
4815
4835
  this.progressBarEl.style.width = `${pct}%`;
4816
4836
  if (this.confidenceRingEl) {
@@ -4866,10 +4886,10 @@ var SmartComplySDK = (() => {
4866
4886
  <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 16px;display:flex;align-items:center;justify-content:center;font-size:32px;
4867
4887
  background:${ok ? "rgba(34,197,94,0.2)" : "rgba(239,68,68,0.2)"};
4868
4888
  border:3px solid ${ok ? "#22c55e" : "#ef4444"};">
4869
- ${ok ? "\u2713" : "\u2715"}
4889
+ ${ok ? "✓" : "✕"}
4870
4890
  </div>
4871
4891
  <div style="font-size:17px;font-weight:700;margin-bottom:8px;">${ok ? "Verification submitted" : "Submission failed"}</div>
4872
- <div style="font-size:12px;opacity:0.6;line-height:1.6;">${ok ? "Hold on while we wrap up\u2026" : "Something went wrong. Please try again."}</div>
4892
+ <div style="font-size:12px;opacity:0.6;line-height:1.6;">${ok ? "Hold on while we wrap up…" : "Something went wrong. Please try again."}</div>
4873
4893
  </div>`;
4874
4894
  setTimeout(resolve, 1800);
4875
4895
  });
@@ -4885,7 +4905,7 @@ var SmartComplySDK = (() => {
4885
4905
  this.overlayEl.style.display = "flex";
4886
4906
  this.overlayEl.innerHTML = `
4887
4907
  <div style="text-align:center;color:#fff;animation:sc-pop-in 0.35s ease;padding:24px;">
4888
- <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 14px;display:flex;align-items:center;justify-content:center;font-size:32px;background:rgba(251,191,36,0.15);border:3px solid #fbbf24;">\u23F1</div>
4908
+ <div style="width:72px;height:72px;border-radius:50%;margin:0 auto 14px;display:flex;align-items:center;justify-content:center;font-size:32px;background:rgba(251,191,36,0.15);border:3px solid #fbbf24;">⏱</div>
4889
4909
  <div style="font-size:17px;font-weight:700;margin-bottom:8px;">Time's Up</div>
4890
4910
  <div style="font-size:12px;opacity:0.6;margin-bottom:18px;">You ran out of time. Please try again.</div>
4891
4911
  <button id="sc-retry-btn" style="padding:11px 28px;border-radius:10px;background:#3b82f6;color:#fff;border:none;cursor:pointer;font-size:14px;font-weight:600;width:100%;max-width:180px;">Try Again</button>
@@ -4924,7 +4944,7 @@ var SmartComplySDK = (() => {
4924
4944
  header.innerHTML = `<div style="color:#fff;font-size:16px;font-weight:700;margin-bottom:6px;">Scan Your ID Document</div><div style="color:rgba(255,255,255,0.6);font-size:12px;line-height:1.6;">Fit your document inside the frame.<br>Make sure all text and corners are visible.</div>`;
4925
4945
  const bottomPanel = document.createElement("div");
4926
4946
  bottomPanel.style.cssText = "position:absolute;bottom:0;left:0;right:0;background:linear-gradient(0deg,rgba(0,0,0,0.92) 0%,rgba(0,0,0,0.6) 70%,transparent 100%);padding:16px;";
4927
- bottomPanel.innerHTML = `<div style="font-size:11px;color:rgba(255,255,255,0.4);text-align:center;margin-bottom:12px;">\u{1F4A1} Good lighting \xB7 No glare \xB7 All 4 corners visible</div><button id="sc-capture-doc-btn" style="width:100%;padding:12px;border-radius:12px;background:#3b82f6;color:#fff;border:none;cursor:pointer;font-size:15px;font-weight:700;margin-bottom:8px;">Capture Document</button><label style="width:100%;display:flex;align-items:center;justify-content:center;gap:6px;padding:9px;border-radius:12px;border:1.5px solid rgba(255,255,255,0.18);cursor:pointer;color:rgba(255,255,255,0.6);font-size:13px;font-weight:500;"><span>\u{1F4C1}</span><span>Upload from gallery instead</span><input id="sc-upload-doc-input" type="file" accept="image/*" style="display:none;" /></label>`;
4947
+ bottomPanel.innerHTML = `<div style="font-size:11px;color:rgba(255,255,255,0.4);text-align:center;margin-bottom:12px;">💡 Good lighting · No glare · All 4 corners visible</div><button id="sc-capture-doc-btn" style="width:100%;padding:12px;border-radius:12px;background:#3b82f6;color:#fff;border:none;cursor:pointer;font-size:15px;font-weight:700;margin-bottom:8px;">Capture Document</button><label style="width:100%;display:flex;align-items:center;justify-content:center;gap:6px;padding:9px;border-radius:12px;border:1.5px solid rgba(255,255,255,0.18);cursor:pointer;color:rgba(255,255,255,0.6);font-size:13px;font-weight:500;"><span>📁</span><span>Upload from gallery instead</span><input id="sc-upload-doc-input" type="file" accept="image/*" style="display:none;" /></label>`;
4928
4948
  docRoot.appendChild(docVideo);
4929
4949
  docRoot.appendChild(guideOverlay);
4930
4950
  docRoot.appendChild(header);
@@ -4997,6 +5017,8 @@ var SmartComplySDK = (() => {
4997
5017
  this.timerEl = null;
4998
5018
  this.overlayEl = null;
4999
5019
  this.actionCueEl = null;
5020
+ this.stepEls = null;
5021
+ this.lastActionRender.clear();
5000
5022
  }
5001
5023
  startTimer(seconds) {
5002
5024
  let remaining = seconds;
@@ -5042,10 +5064,12 @@ var SmartComplySDK = (() => {
5042
5064
  */
5043
5065
  async create(params) {
5044
5066
  const formData = new FormData();
5045
- const rawIdentifier = params.identifier || `ID-${Date.now()}`;
5046
- const safeIdentifier = rawIdentifier.length > 20 ? rawIdentifier.slice(0, 20) : rawIdentifier;
5047
- formData.append("identifier", safeIdentifier);
5048
- formData.append("identifier_type", params.identifier_type);
5067
+ if (!params.identity_check) {
5068
+ const rawIdentifier = params.identifier || `ID-${Date.now()}`;
5069
+ const safeIdentifier = rawIdentifier.length > 20 ? rawIdentifier.slice(0, 20) : rawIdentifier;
5070
+ formData.append("identifier", safeIdentifier);
5071
+ formData.append("identifier_type", params.identifier_type);
5072
+ }
5049
5073
  formData.append("country", params.country);
5050
5074
  formData.append(
5051
5075
  "challenge_actions",
@@ -5121,7 +5145,10 @@ var SmartComplySDK = (() => {
5121
5145
  }
5122
5146
  /**
5123
5147
  * Poll the public SDK status endpoint for the final verification result.
5124
- * Safe to call after the session has been revoked (no auth required).
5148
+ * Safe to call after the session has been revoked (no auth required) —
5149
+ * the ocr_* fields below are only populated by the backend when a live
5150
+ * session token is still attached (see HttpClient.publicGet), since they
5151
+ * carry PII (name, document number, face thumbnail).
5125
5152
  *
5126
5153
  * GET /v1/sdk/liveness/<entryId>/sdk-result/
5127
5154
  */
@@ -5330,7 +5357,7 @@ var SmartComplySDK = (() => {
5330
5357
  ui2.updateInstruction(getLabel(current));
5331
5358
  }
5332
5359
  } else {
5333
- ui2.updateInstruction("All actions completed! \u2713");
5360
+ ui2.updateInstruction("All actions completed! ✓");
5334
5361
  }
5335
5362
  if (actionDetector.allCompleted()) {
5336
5363
  clearTimeout(timeout);
@@ -5362,7 +5389,7 @@ var SmartComplySDK = (() => {
5362
5389
  });
5363
5390
  });
5364
5391
  }
5365
- ui2.updateInstruction("Almost done \u2014 hold still...");
5392
+ ui2.updateInstruction("Almost done — hold still...");
5366
5393
  await new Promise((r2) => setTimeout(r2, 800));
5367
5394
  const autoshotBlob = await this.captureFrame(videoEl);
5368
5395
  if (!autoshotBlob || autoshotBlob.size === 0) {
@@ -5881,7 +5908,7 @@ var SmartComplySDK = (() => {
5881
5908
  const docLabel = this.getDocumentLabel(documentType);
5882
5909
  const requiresBack = this.shouldCaptureBackSide(documentType);
5883
5910
  const isCapturingFront = this.currentSide === "front";
5884
- const sideLabel = requiresBack ? isCapturingFront ? " \u2014 Front side" : " \u2014 Back side" : "";
5911
+ const sideLabel = requiresBack ? isCapturingFront ? " — Front side" : " — Back side" : "";
5885
5912
  const headerRow = document.createElement("div");
5886
5913
  headerRow.style.cssText = `
5887
5914
  display:flex;align-items:center;gap:14px;
@@ -5902,7 +5929,7 @@ var SmartComplySDK = (() => {
5902
5929
  titleEl.textContent = `Capture your ${docLabel}`;
5903
5930
  const subEl = document.createElement("div");
5904
5931
  subEl.style.cssText = `color:${theme.textSecondary};font-size:12px;margin-top:2px;`;
5905
- subEl.textContent = requiresBack ? isCapturingFront ? "Step 1 of 2 \u2014 front side" : "Step 2 of 2 \u2014 back side" : "Choose how to provide your document";
5932
+ subEl.textContent = requiresBack ? isCapturingFront ? "Step 1 of 2 — front side" : "Step 2 of 2 — back side" : "Choose how to provide your document";
5906
5933
  titleBlock.appendChild(titleEl);
5907
5934
  titleBlock.appendChild(subEl);
5908
5935
  headerRow.appendChild(iconBox);
@@ -5923,7 +5950,7 @@ var SmartComplySDK = (() => {
5923
5950
  transition:all 0.15s ease;min-height:80px;
5924
5951
  box-shadow:0 4px 14px ${theme.primary}30;
5925
5952
  `;
5926
- cameraBtn.innerHTML = `<span style="font-size:26px;">\u{1F4F7}</span><span>Take Photo</span><span style="font-size:10px;opacity:0.8;font-weight:500;">Use camera</span>`;
5953
+ cameraBtn.innerHTML = `<span style="font-size:26px;">📷</span><span>Take Photo</span><span style="font-size:10px;opacity:0.8;font-weight:500;">Use camera</span>`;
5927
5954
  cameraBtn.addEventListener("mouseenter", () => {
5928
5955
  cameraBtn.style.opacity = "0.9";
5929
5956
  cameraBtn.style.transform = "translateY(-1px)";
@@ -5945,7 +5972,7 @@ var SmartComplySDK = (() => {
5945
5972
  font-size:13px;font-weight:600;font-family:inherit;
5946
5973
  transition:all 0.15s ease;min-height:80px;
5947
5974
  `;
5948
- uploadBtn.innerHTML = `<span style="font-size:26px;">\u{1F5BC}\uFE0F</span><span>From Gallery</span><span style="font-size:10px;color:${theme.textMuted || theme.textSecondary};font-weight:500;">Upload file</span>`;
5975
+ uploadBtn.innerHTML = `<span style="font-size:26px;">🖼️</span><span>From Gallery</span><span style="font-size:10px;color:${theme.textMuted || theme.textSecondary};font-weight:500;">Upload file</span>`;
5949
5976
  uploadBtn.addEventListener("mouseenter", () => {
5950
5977
  uploadBtn.style.borderColor = theme.primary;
5951
5978
  uploadBtn.style.transform = "translateY(-1px)";
@@ -5979,7 +6006,7 @@ var SmartComplySDK = (() => {
5979
6006
  tipItems.forEach((t2) => {
5980
6007
  const row = document.createElement("div");
5981
6008
  row.style.cssText = `display:flex;align-items:center;gap:5px;font-size:11px;color:${theme.textSecondary};`;
5982
- row.innerHTML = `<span style="color:${theme.primary};font-weight:700;flex-shrink:0;">\u2713</span><span>${t2}</span>`;
6009
+ row.innerHTML = `<span style="color:${theme.primary};font-weight:700;flex-shrink:0;">✓</span><span>${t2}</span>`;
5983
6010
  tipsGrid.appendChild(row);
5984
6011
  });
5985
6012
  tips.appendChild(tipsGrid);
@@ -5993,7 +6020,7 @@ var SmartComplySDK = (() => {
5993
6020
  display:flex;align-items:center;gap:8px;
5994
6021
  font-size:12px;color:${theme.textSecondary};line-height:1.5;
5995
6022
  `;
5996
- notice.innerHTML = `<span style="font-size:16px;flex-shrink:0;">\u2139\uFE0F</span><span>You'll capture both the <strong style="color:${theme.text}">front</strong> and <strong style="color:${theme.text}">back</strong> of this document.</span>`;
6023
+ notice.innerHTML = `<span style="font-size:16px;flex-shrink:0;">ℹ️</span><span>You'll capture both the <strong style="color:${theme.text}">front</strong> and <strong style="color:${theme.text}">back</strong> of this document.</span>`;
5997
6024
  this.root.appendChild(notice);
5998
6025
  }
5999
6026
  const fileInput = document.createElement("input");
@@ -6019,10 +6046,10 @@ var SmartComplySDK = (() => {
6019
6046
  /** Returns an appropriate emoji icon for the document type. */
6020
6047
  _docIcon(documentType) {
6021
6048
  const t2 = documentType.toLowerCase();
6022
- if (t2.includes("passport")) return "\u{1F4D8}";
6023
- if (t2.includes("driver") || t2.includes("licen")) return "\u{1F697}";
6024
- if (t2.includes("voter") || t2.includes("pvc")) return "\u{1F5F3}\uFE0F";
6025
- return "\u{1FAAA}";
6049
+ if (t2.includes("passport")) return "📘";
6050
+ if (t2.includes("driver") || t2.includes("licen")) return "🚗";
6051
+ if (t2.includes("voter") || t2.includes("pvc")) return "🗳️";
6052
+ return "🪪";
6026
6053
  }
6027
6054
  renderCameraView(container, theme, documentType) {
6028
6055
  const wrapper = document.createElement("div");
@@ -6232,12 +6259,12 @@ var SmartComplySDK = (() => {
6232
6259
  `;
6233
6260
  const issueLine = document.createElement("div");
6234
6261
  issueLine.style.cssText = "font-weight:700;color:#b8860b;";
6235
- issueLine.textContent = `\u26A0\uFE0F ${quality.message}`;
6262
+ issueLine.textContent = `⚠️ ${quality.message}`;
6236
6263
  warn.appendChild(issueLine);
6237
6264
  if (quality.recommendations.length > 0) {
6238
6265
  const rec = document.createElement("div");
6239
6266
  rec.style.cssText = "margin-top:4px;color:" + theme.textSecondary + ";";
6240
- rec.textContent = quality.recommendations.join(" \xB7 ");
6267
+ rec.textContent = quality.recommendations.join(" · ");
6241
6268
  warn.appendChild(rec);
6242
6269
  }
6243
6270
  this.root.appendChild(warn);
@@ -6253,7 +6280,7 @@ var SmartComplySDK = (() => {
6253
6280
  this.root.innerHTML = "";
6254
6281
  this.renderChoiceScreen(container, theme, documentType);
6255
6282
  });
6256
- const useBtn = this.createButton(qualityIsPoor ? "Use Anyway \u26A0" : "Use Photo \u2713", theme, !qualityIsPoor);
6283
+ const useBtn = this.createButton(qualityIsPoor ? "Use Anyway ⚠" : "Use Photo ✓", theme, !qualityIsPoor);
6257
6284
  useBtn.style.flex = "1";
6258
6285
  useBtn.addEventListener("click", () => {
6259
6286
  if (img._blobUrl) {
@@ -6399,7 +6426,7 @@ var SmartComplySDK = (() => {
6399
6426
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
6400
6427
  font-size:28px;animation:pulse 2s ease-in-out infinite;
6401
6428
  `;
6402
- centerIcon.textContent = "\u{1F4C4}";
6429
+ centerIcon.textContent = "📄";
6403
6430
  spinnerContainer.appendChild(centerIcon);
6404
6431
  this.root.appendChild(spinnerContainer);
6405
6432
  const loadingText = document.createElement("div");
@@ -6434,7 +6461,7 @@ var SmartComplySDK = (() => {
6434
6461
  color:#ff4444;font-size:14px;margin-top:16px;animation:shake 0.5s ease-in-out;
6435
6462
  `;
6436
6463
  errorContainer.innerHTML = `
6437
- <span style="font-size:18px;">\u26A0\uFE0F</span>
6464
+ <span style="font-size:18px;">⚠️</span>
6438
6465
  <span>${message}</span>
6439
6466
  `;
6440
6467
  if (!document.head.querySelector("style[data-shake-animation]")) {
@@ -6619,13 +6646,13 @@ var SmartComplySDK = (() => {
6619
6646
 
6620
6647
  // src/flow/SmartComplyFlow.ts
6621
6648
  var COUNTRY_LABELS = {
6622
- nigeria: "\xF0\u0178\u2021\xB3\xF0\u0178\u2021\xAC Nigeria",
6623
- global: "\xF0\u0178\u0152\x8D Other Countries",
6624
- ghana: "\xF0\u0178\u2021\xAC\xF0\u0178\u2021\xAD Ghana",
6625
- kenya: "\xF0\u0178\u2021\xB0\xF0\u0178\u2021\xAA Kenya",
6626
- south_africa: "\xF0\u0178\u2021\xBF\xF0\u0178\u2021\xA6 South Africa",
6627
- united_states: "\xF0\u0178\u2021\xBA\xF0\u0178\u2021\xB8 United States",
6628
- united_kingdom: "\xF0\u0178\u2021\xAC\xF0\u0178\u2021\xA7 United Kingdom"
6649
+ nigeria: "🇳🇬 Nigeria",
6650
+ global: "🌍 Other Countries",
6651
+ ghana: "🇬🇭 Ghana",
6652
+ kenya: "🇰🇪 Kenya",
6653
+ south_africa: "🇿🇦 South Africa",
6654
+ united_states: "🇺🇸 United States",
6655
+ united_kingdom: "🇬🇧 United Kingdom"
6629
6656
  };
6630
6657
  function isUploadFieldType(type) {
6631
6658
  return type === "upload" || type === "image" || type === "file";
@@ -6639,37 +6666,37 @@ var SmartComplySDK = (() => {
6639
6666
  return t2.includes("voter") || t2.includes("driver") || t2.includes("license") || t2.includes("national id") || t2.includes("national id card");
6640
6667
  };
6641
6668
  if (u2.includes("BVN") || u2.includes("BANK VERIFICATION")) {
6642
- return { icon: "\xF0\u0178\x8F\xA6", desc: "Enter your 11-digit Bank Verification Number (BVN)", requiresBack: false };
6669
+ return { icon: "🏦", desc: "Enter your 11-digit Bank Verification Number (BVN)", requiresBack: false };
6643
6670
  }
6644
6671
  if (u2.includes("NIN") || u2.includes("NATIONAL IDENTITY NUMBER")) {
6645
- return { icon: "\xF0\u0178\u2020\u201D", desc: "Enter your 11-digit National Identification Number (NIN)", requiresBack: false };
6672
+ return { icon: "🆔", desc: "Enter your 11-digit National Identification Number (NIN)", requiresBack: false };
6646
6673
  }
6647
6674
  if (u2.includes("GHANA")) {
6648
- if (isDocumentFlow) return { icon: "\xF0\u0178\xAA\xAA", desc: "Capture or upload your Ghana Card", requiresBack: true };
6649
- return { icon: "\xF0\u0178\xAA\xAA", desc: "Enter your Ghana Card number", requiresBack: false };
6675
+ if (isDocumentFlow) return { icon: "🪪", desc: "Capture or upload your Ghana Card", requiresBack: true };
6676
+ return { icon: "🪪", desc: "Enter your Ghana Card number", requiresBack: false };
6650
6677
  }
6651
6678
  if (u2.includes("SSNIT"))
6652
- return { icon: "\xF0\u0178\x8F\u203A\xEF\xB8\x8F", desc: "Enter your SSNIT number", requiresBack: false };
6679
+ return { icon: "🏛️", desc: "Enter your SSNIT number", requiresBack: false };
6653
6680
  if (u2.includes("KENYA") || u2.includes("NATIONAL") && u2.includes("KENYA"))
6654
- return { icon: "\xF0\u0178\u2020\u201D", desc: "Enter your Kenya National ID number", requiresBack: false };
6681
+ return { icon: "🆔", desc: "Enter your Kenya National ID number", requiresBack: false };
6655
6682
  if (u2.includes("TIN") || u2.includes("TAX IDENTIFICATION"))
6656
- return { icon: "\xF0\u0178\xA7\xBE", desc: "Enter your Tax Identification Number (TIN)", requiresBack: false };
6683
+ return { icon: "🧾", desc: "Enter your Tax Identification Number (TIN)", requiresBack: false };
6657
6684
  if (u2.includes("CAC") || u2.includes("CORPORATE AFFAIRS") || u2.includes("COMPANY"))
6658
- return { icon: "\xF0\u0178\x8F\xA2", desc: advanced ? "Enter RC number, company name & type" : "Enter your company registration number", requiresBack: false };
6685
+ return { icon: "🏢", desc: advanced ? "Enter RC number, company name & type" : "Enter your company registration number", requiresBack: false };
6659
6686
  if (u2.includes("VOTER") || u2.includes("PVC")) {
6660
6687
  const requiresBack = requiresBackSide(typeName);
6661
6688
  return {
6662
- icon: "\xF0\u0178\u2014\xB3\xEF\xB8\x8F",
6689
+ icon: "🗳️",
6663
6690
  desc: isDocumentFlow ? `Capture or upload your voter's card${requiresBack ? " (front & back)" : ""}` : "Enter your voter ID number",
6664
6691
  requiresBack: isDocumentFlow ? requiresBack : false
6665
6692
  };
6666
6693
  }
6667
6694
  if (u2.includes("PASSPORT"))
6668
- return { icon: "\xF0\u0178\u201C\u02DC", desc: isDocumentFlow ? "Capture or upload your passport" : "Enter your passport number", requiresBack: false };
6695
+ return { icon: "📘", desc: isDocumentFlow ? "Capture or upload your passport" : "Enter your passport number", requiresBack: false };
6669
6696
  if (u2.includes("DRIVER") || u2.includes("LICENSE") || u2.includes("LICENCE")) {
6670
6697
  const requiresBack = requiresBackSide(typeName);
6671
6698
  return {
6672
- icon: "\xF0\u0178\u0161\u2014",
6699
+ icon: "🚗",
6673
6700
  desc: isDocumentFlow ? `Capture or upload your driver's license${requiresBack ? " (front & back)" : ""}` : "Enter your driver's license number",
6674
6701
  requiresBack: isDocumentFlow ? requiresBack : false
6675
6702
  };
@@ -6677,15 +6704,15 @@ var SmartComplySDK = (() => {
6677
6704
  if (u2.includes("NATIONAL ID") || u2.includes("NATIONAL") && u2.includes("CARD")) {
6678
6705
  const requiresBack = requiresBackSide(typeName);
6679
6706
  return {
6680
- icon: "\xF0\u0178\xAA\xAA",
6707
+ icon: "🪪",
6681
6708
  desc: isDocumentFlow ? `Capture or upload your ID card${requiresBack ? " (front & back)" : ""}` : "Enter your National ID number",
6682
6709
  requiresBack: isDocumentFlow ? requiresBack : false
6683
6710
  };
6684
6711
  }
6685
6712
  if (u2.includes("LIVENESS") || u2.includes("FACE COMPARISON") || u2.includes("FACE MATCH"))
6686
- return { icon: "\xF0\u0178\xA4\xB3", desc: "We'll capture a short selfie video to verify you", requiresBack: false };
6713
+ return { icon: "🤳", desc: "We'll capture a short selfie video to verify you", requiresBack: false };
6687
6714
  return {
6688
- icon: isDocumentFlow ? "\xF0\u0178\u201C\u201E" : "\xF0\u0178\u2020\u201D",
6715
+ icon: isDocumentFlow ? "📄" : "🆔",
6689
6716
  desc: isDocumentFlow ? "Capture or upload your document" : "Enter your ID number",
6690
6717
  requiresBack: false
6691
6718
  };
@@ -7097,7 +7124,7 @@ var SmartComplySDK = (() => {
7097
7124
  display:flex;align-items:center;justify-content:center;
7098
7125
  font-size:22px;
7099
7126
  `;
7100
- centre.textContent = "\u{1F6E1}\uFE0F";
7127
+ centre.textContent = "🛡️";
7101
7128
  spinnerWrap.appendChild(ring);
7102
7129
  spinnerWrap.appendChild(centre);
7103
7130
  container.appendChild(spinnerWrap);
@@ -7124,7 +7151,7 @@ var SmartComplySDK = (() => {
7124
7151
  background:linear-gradient(135deg,${this.theme.primary}22,${this.theme.primaryGlow});
7125
7152
  border:1.5px solid ${this.theme.primary}33;
7126
7153
  `;
7127
- iconWrap.textContent = isDocFlow ? "\xF0\u0178\xAA\xAA" : "\xF0\u0178\u203A\xA1\xEF\xB8\x8F";
7154
+ iconWrap.textContent = isDocFlow ? "🪪" : "🛡️";
7128
7155
  topRow.appendChild(iconWrap);
7129
7156
  const badge = document.createElement("div");
7130
7157
  badge.style.cssText = `
@@ -7135,7 +7162,7 @@ var SmartComplySDK = (() => {
7135
7162
  color:${this.theme.primary};
7136
7163
  border:1px solid ${this.theme.primary}30;
7137
7164
  `;
7138
- badge.textContent = isDocFlow ? "\xF0\u0178\u201C\u201E Document Verification" : "\xF0\u0178\u201D\x8D Data Verification";
7165
+ badge.textContent = isDocFlow ? "📄 Document Verification" : "🔍 Data Verification";
7139
7166
  topRow.appendChild(badge);
7140
7167
  container.appendChild(topRow);
7141
7168
  const titleWrap = document.createElement("div");
@@ -7157,13 +7184,13 @@ var SmartComplySDK = (() => {
7157
7184
  titleWrap.appendChild(desc);
7158
7185
  container.appendChild(titleWrap);
7159
7186
  const steps = isDocFlow ? [
7160
- { icon: "\xF0\u0178\xAA\xAA", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
7161
- { icon: "\xF0\u0178\u201C\xB7", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
7162
- { icon: "\xF0\u0178\xA4\xB3", text: "Face check", sub: "Quick selfie to confirm it's you" }
7187
+ { icon: "🪪", text: "Choose your document type", sub: "Passport, National ID, Driver License" },
7188
+ { icon: "📷", text: "Scan your document", sub: "Upload or capture a photo of your ID" },
7189
+ { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" }
7163
7190
  ] : [
7164
- { icon: "\xF0\u0178\u2020\u201D", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
7165
- { icon: "\xF0\u0178\u201C\x9D", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
7166
- { icon: "\xF0\u0178\xA4\xB3", text: "Face check", sub: "Quick selfie to confirm it's you" }
7191
+ { icon: "🆔", text: "Choose your ID type", sub: "NIN, BVN, Voter's Card and more" },
7192
+ { icon: "📝", text: "Enter your ID details", sub: "Exactly as shown on your ID" },
7193
+ { icon: "🤳", text: "Face check", sub: "Quick selfie to confirm it's you" }
7167
7194
  ];
7168
7195
  const stepsWrap = document.createElement("div");
7169
7196
  stepsWrap.style.cssText = `
@@ -7203,7 +7230,7 @@ var SmartComplySDK = (() => {
7203
7230
  stepsWrap.appendChild(row);
7204
7231
  });
7205
7232
  container.appendChild(stepsWrap);
7206
- const btn = this.createPrimaryButton("Get Started \xE2\u2020\u2019");
7233
+ const btn = this.createPrimaryButton("Get Started →");
7207
7234
  btn.style.cssText += "margin-top:2px;";
7208
7235
  btn.addEventListener("click", () => this.showStep("country"));
7209
7236
  container.appendChild(btn);
@@ -7212,7 +7239,7 @@ var SmartComplySDK = (() => {
7212
7239
  display:flex;align-items:center;gap:6px;
7213
7240
  color:${this.theme.textMuted};font-size:10.5px;
7214
7241
  `;
7215
- trust.textContent = "\xF0\u0178\u201D\u2019 End-to-end encrypted";
7242
+ trust.textContent = "🔒 End-to-end encrypted";
7216
7243
  container.appendChild(trust);
7217
7244
  }
7218
7245
  // ── Country Select ──────────────────────────────────────────────
@@ -7265,7 +7292,7 @@ var SmartComplySDK = (() => {
7265
7292
  const requiresBack = requiresBackFromBackend ?? info.requiresBack;
7266
7293
  let subtitle2 = info.desc;
7267
7294
  if (requiresBack && isThisDocFlow) {
7268
- subtitle2 += " \xE2\u0161\xA0\xEF\xB8\x8F Both sides required";
7295
+ subtitle2 += " ⚠️ Both sides required";
7269
7296
  }
7270
7297
  const displayName = typeName.replace(/\s*with\s+face\s*/gi, " ").replace(/\s*\(NIN\)\s*/gi, " ").replace(/\s*\(BVN\)\s*/gi, " ").replace(/\s{2,}/g, " ").trim();
7271
7298
  const card = this.createOptionCard(
@@ -7328,13 +7355,13 @@ var SmartComplySDK = (() => {
7328
7355
  { match: "BVN", rule: { minLen: 11, maxLen: 11, numeric: true, hint: "BVN must be exactly 11 digits" } },
7329
7356
  { match: "NIN", rule: { minLen: 11, maxLen: 11, numeric: true, hint: "NIN must be exactly 11 digits" } },
7330
7357
  { match: "NATIONAL IDENTITY", rule: { minLen: 11, maxLen: 11, numeric: true, hint: "NIN must be exactly 11 digits" } },
7331
- { match: "PASSPORT", rule: { minLen: 6, maxLen: 20, alphanumeric: true, hint: "Passport number must be 6\xE2\u20AC\u201C20 alphanumeric characters" } },
7332
- { match: "DRIVER", rule: { minLen: 3, maxLen: 30, alphanumeric: true, hint: "Licence number must be 3\xE2\u20AC\u201C30 alphanumeric characters" } },
7333
- { match: "VOTER", rule: { minLen: 6, maxLen: 30, alphanumeric: true, hint: "Voter ID must be 6\xE2\u20AC\u201C30 alphanumeric characters" } },
7334
- { match: "GHANA", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "Ghana Card number must be 8\xE2\u20AC\u201C20 alphanumeric characters" } },
7335
- { match: "SSNIT", rule: { minLen: 7, maxLen: 15, alphanumeric: true, hint: "SSNIT number must be 7\xE2\u20AC\u201C15 alphanumeric characters" } },
7336
- { match: "TIN", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "TIN must be 8\xE2\u20AC\u201C20 characters" } },
7337
- { match: "KRA", rule: { minLen: 10, maxLen: 12, alphanumeric: true, hint: "KRA PIN must be 10\xE2\u20AC\u201C12 characters" } }
7358
+ { match: "PASSPORT", rule: { minLen: 6, maxLen: 20, alphanumeric: true, hint: "Passport number must be 6–20 alphanumeric characters" } },
7359
+ { match: "DRIVER", rule: { minLen: 3, maxLen: 30, alphanumeric: true, hint: "Licence number must be 3–30 alphanumeric characters" } },
7360
+ { match: "VOTER", rule: { minLen: 6, maxLen: 30, alphanumeric: true, hint: "Voter ID must be 6–30 alphanumeric characters" } },
7361
+ { match: "GHANA", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "Ghana Card number must be 8–20 alphanumeric characters" } },
7362
+ { match: "SSNIT", rule: { minLen: 7, maxLen: 15, alphanumeric: true, hint: "SSNIT number must be 7–15 alphanumeric characters" } },
7363
+ { match: "TIN", rule: { minLen: 8, maxLen: 20, alphanumeric: true, hint: "TIN must be 8–20 characters" } },
7364
+ { match: "KRA", rule: { minLen: 10, maxLen: 12, alphanumeric: true, hint: "KRA PIN must be 10–12 characters" } }
7338
7365
  ];
7339
7366
  function getFieldRule(label) {
7340
7367
  const upper = label.toUpperCase();
@@ -7620,7 +7647,7 @@ var SmartComplySDK = (() => {
7620
7647
  this._prewarmCamera();
7621
7648
  const iconWrap = document.createElement("div");
7622
7649
  iconWrap.style.cssText = `width:64px;height:64px;border-radius:50%;background:${this.theme.primary}15;border:2px solid ${this.theme.primary}30;display:flex;align-items:center;justify-content:center;font-size:28px;`;
7623
- iconWrap.textContent = "\xF0\u0178\u203A\xA1\xEF\xB8\x8F";
7650
+ iconWrap.textContent = "🛡️";
7624
7651
  container.appendChild(iconWrap);
7625
7652
  const title = document.createElement("h2");
7626
7653
  title.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
@@ -7657,7 +7684,7 @@ var SmartComplySDK = (() => {
7657
7684
  sub.textContent = "Your details have been confirmed. Please continue to the face check.";
7658
7685
  container.appendChild(sub);
7659
7686
  }
7660
- const yesBtn = this.createPrimaryButton("Yes, that's me \xE2\u20AC\u201D continue");
7687
+ const yesBtn = this.createPrimaryButton("Yes, that's me — continue");
7661
7688
  yesBtn.addEventListener("click", () => {
7662
7689
  this._confirmRetries = 0;
7663
7690
  this.showStep("liveness");
@@ -7684,7 +7711,7 @@ var SmartComplySDK = (() => {
7684
7711
  this._prewarmCamera();
7685
7712
  const iconWrap = document.createElement("div");
7686
7713
  iconWrap.style.cssText = `width:64px;height:64px;border-radius:50%;background:${this.theme.primary}15;border:2px solid ${this.theme.primary}30;display:flex;align-items:center;justify-content:center;font-size:28px;`;
7687
- iconWrap.textContent = "\xF0\u0178\u201C\u201E";
7714
+ iconWrap.textContent = "📄";
7688
7715
  container.appendChild(iconWrap);
7689
7716
  const title = document.createElement("h2");
7690
7717
  title.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
@@ -7707,7 +7734,7 @@ var SmartComplySDK = (() => {
7707
7734
  if (this._ocrExpirySoon && !this._ocrIsExpired) {
7708
7735
  const warn = document.createElement("div");
7709
7736
  warn.style.cssText = `width:100%;padding:10px 14px;border-radius:10px;background:${this.theme.warning}18;border:1px solid ${this.theme.warning}40;color:${this.theme.warning};font-size:12px;text-align:left;line-height:1.5;`;
7710
- warn.textContent = "\xE2\u0161\xA0\xEF\xB8\x8F Your document expires soon. Some services may not accept it, but you can still continue.";
7737
+ warn.textContent = "⚠️ Your document expires soon. Some services may not accept it, but you can still continue.";
7711
7738
  container.appendChild(warn);
7712
7739
  }
7713
7740
  const card = document.createElement("div");
@@ -7770,18 +7797,18 @@ var SmartComplySDK = (() => {
7770
7797
  ring.style.cssText = `position:absolute;inset:0;border-radius:50%;border:3px solid ${this.theme.border};border-top-color:${this.theme.primary};animation:sc-spin 0.9s linear infinite;`;
7771
7798
  const centre = document.createElement("div");
7772
7799
  centre.style.cssText = "position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;";
7773
- centre.textContent = "\xF0\u0178\u201C\u201E";
7800
+ centre.textContent = "📄";
7774
7801
  spinnerWrap.appendChild(ring);
7775
7802
  spinnerWrap.appendChild(centre);
7776
7803
  container.appendChild(spinnerWrap);
7777
7804
  const statusEl = document.createElement("div");
7778
7805
  statusEl.setAttribute("aria-live", "polite");
7779
7806
  statusEl.style.cssText = `color:${this.theme.text};font-size:15px;font-weight:600;`;
7780
- statusEl.textContent = "Reading your document\xE2\u20AC\xA6";
7807
+ statusEl.textContent = "Reading your document…";
7781
7808
  container.appendChild(statusEl);
7782
7809
  const subEl = document.createElement("div");
7783
7810
  subEl.style.cssText = `color:${this.theme.textSecondary};font-size:12px;max-width:260px;line-height:1.5;`;
7784
- subEl.textContent = "This usually takes 5\xE2\u20AC\u201C15 seconds. Please wait.";
7811
+ subEl.textContent = "This usually takes 5–15 seconds. Please wait.";
7785
7812
  container.appendChild(subEl);
7786
7813
  if (!this.livenessEntryId) {
7787
7814
  this.showErrorStep("Document upload failed. Please try again.");
@@ -7826,8 +7853,8 @@ var SmartComplySDK = (() => {
7826
7853
  if (polls < MAX_POLLS && !this.isDestroyed) {
7827
7854
  this._ocrPollTimer = setTimeout(poll, 2e3);
7828
7855
  } else if (!this.isDestroyed) {
7829
- statusEl.textContent = "Taking longer than usual\xE2\u20AC\xA6";
7830
- subEl.textContent = "We'll continue \xE2\u20AC\u201D you can confirm your details on the next screen.";
7856
+ statusEl.textContent = "Taking longer than usual…";
7857
+ subEl.textContent = "We'll continue — you can confirm your details on the next screen.";
7831
7858
  this._ocrPollTimer = setTimeout(() => {
7832
7859
  if (!this.isDestroyed) this.showStep("document_confirm");
7833
7860
  }, 2e3);
@@ -7846,7 +7873,7 @@ var SmartComplySDK = (() => {
7846
7873
  container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:20px 0;";
7847
7874
  const icon = document.createElement("div");
7848
7875
  icon.style.cssText = `width:72px;height:72px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:28px;`;
7849
- icon.textContent = "\xF0\u0178\u201C\u2026";
7876
+ icon.textContent = "📅";
7850
7877
  container.appendChild(icon);
7851
7878
  const t2 = document.createElement("h2");
7852
7879
  t2.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
@@ -7875,7 +7902,7 @@ var SmartComplySDK = (() => {
7875
7902
  container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:20px 0;";
7876
7903
  const icon = document.createElement("div");
7877
7904
  icon.style.cssText = `width:72px;height:72px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:28px;`;
7878
- icon.textContent = "\xF0\u0178\u201D\x8D";
7905
+ icon.textContent = "🔍";
7879
7906
  container.appendChild(icon);
7880
7907
  const t2 = document.createElement("h2");
7881
7908
  t2.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
@@ -7908,7 +7935,7 @@ var SmartComplySDK = (() => {
7908
7935
  });
7909
7936
  const iconWrap = document.createElement("div");
7910
7937
  iconWrap.style.cssText = `width:80px;height:80px;border-radius:50%;background:${this.theme.successBg};border:3px solid ${this.theme.success};display:flex;align-items:center;justify-content:center;font-size:36px;font-weight:700;color:${this.theme.success};animation:sc-pop 0.4s ease;`;
7911
- iconWrap.textContent = "\xE2\u0153\u201C";
7938
+ iconWrap.textContent = "✓";
7912
7939
  container.appendChild(iconWrap);
7913
7940
  const title = document.createElement("h2");
7914
7941
  title.style.cssText = `color:${this.theme.text};font-size:22px;font-weight:700;margin:0;`;
@@ -7921,7 +7948,7 @@ var SmartComplySDK = (() => {
7921
7948
  container.appendChild(desc);
7922
7949
  const info = document.createElement("div");
7923
7950
  info.style.cssText = `color:${this.theme.textMuted};font-size:11px;display:flex;align-items:center;gap:4px;`;
7924
- info.textContent = "\xF0\u0178\u201D\u2019 Your data is encrypted and secure";
7951
+ info.textContent = "🔒 Your data is encrypted and secure";
7925
7952
  container.appendChild(info);
7926
7953
  const doneBtn = this.createPrimaryButton("Close");
7927
7954
  doneBtn.addEventListener("click", () => {
@@ -7934,7 +7961,7 @@ var SmartComplySDK = (() => {
7934
7961
  container.style.cssText += "display:flex;flex-direction:column;align-items:center;text-align:center;gap:14px;padding:24px 0;";
7935
7962
  const icon = document.createElement("div");
7936
7963
  icon.style.cssText = `width:72px;height:72px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:28px;`;
7937
- icon.textContent = "\xE2\u0161\xA0\xEF\xB8\x8F";
7964
+ icon.textContent = "⚠️";
7938
7965
  container.appendChild(icon);
7939
7966
  const t2 = document.createElement("h2");
7940
7967
  t2.style.cssText = `color:${this.theme.text};font-size:18px;font-weight:700;margin:0;`;
@@ -7990,7 +8017,7 @@ var SmartComplySDK = (() => {
7990
8017
  <div style="display:flex;flex-direction:column;align-items:center;gap:14px;padding:28px 20px;">
7991
8018
  <div style="position:relative;width:52px;height:52px;">
7992
8019
  <div style="position:absolute;inset:0;border-radius:50%;border:3px solid ${this.theme.border};border-top-color:${this.theme.primary};animation:sc-spin 0.8s linear infinite;"></div>
7993
- <div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">\xF0\u0178\u201D\x8D</div>
8020
+ <div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔍</div>
7994
8021
  </div>
7995
8022
  <div style="color:${this.theme.text};font-size:14px;font-weight:600;">Scanning document...</div>
7996
8023
  <div style="color:${this.theme.textSecondary};font-size:12px;text-align:center;max-width:200px;line-height:1.5;">Running OCR and verifying your identity</div>
@@ -8048,7 +8075,7 @@ var SmartComplySDK = (() => {
8048
8075
  <div style="display:flex;flex-direction:column;align-items:center;gap:16px;padding:28px 20px;text-align:center;">
8049
8076
  <div style="position:relative;width:52px;height:52px;">
8050
8077
  <div style="position:absolute;inset:0;border-radius:50%;border:3px solid ${this.theme.border};border-top-color:${this.theme.primary};animation:sc-spin 0.8s linear infinite;"></div>
8051
- <div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">\xF0\u0178\u201D\u201E</div>
8078
+ <div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:20px;">🔄</div>
8052
8079
  </div>
8053
8080
  <div style="color:${this.theme.text};font-size:14px;font-weight:600;">Retrying...</div>
8054
8081
  <div style="color:${this.theme.textSecondary};font-size:12px;max-width:240px;line-height:1.5;">Attempt ${retryCount} of ${maxRetries}</div>
@@ -8089,7 +8116,7 @@ var SmartComplySDK = (() => {
8089
8116
  wrap.setAttribute("role", "alert");
8090
8117
  const icon = document.createElement("div");
8091
8118
  icon.style.cssText = `width:56px;height:56px;border-radius:50%;background:${this.theme.errorBg};border:3px solid ${this.theme.error};display:flex;align-items:center;justify-content:center;font-size:26px;`;
8092
- icon.textContent = "\xF0\u0178\u201D\x8D";
8119
+ icon.textContent = "🔍";
8093
8120
  wrap.appendChild(icon);
8094
8121
  const titleEl = document.createElement("div");
8095
8122
  titleEl.style.cssText = `color:${this.theme.text};font-size:14px;font-weight:700;`;
@@ -8130,8 +8157,8 @@ var SmartComplySDK = (() => {
8130
8157
  livenessContainer.style.cssText = "margin:8px 0;width:100%;";
8131
8158
  container.appendChild(livenessContainer);
8132
8159
  const isDataVerification = !!this.identityCheckId;
8133
- const identifier = isDataVerification ? `SES-${Date.now()}` : this.idNumber || Object.values(this.collectedFields)[0] || this.selectedIdType || `DOC-${Date.now()}`;
8134
- const identifierType = isDataVerification ? "session" : this.selectedIdType;
8160
+ const identifier = isDataVerification ? "" : this.idNumber || Object.values(this.collectedFields)[0] || this.selectedIdType || `DOC-${Date.now()}`;
8161
+ const identifierType = isDataVerification ? "" : this.selectedIdType;
8135
8162
  const COUNTRY_CODES = {
8136
8163
  nigeria: "NG",
8137
8164
  ghana: "GH",
@@ -8189,7 +8216,7 @@ var SmartComplySDK = (() => {
8189
8216
  const isDocQuality = /blurry|blur|quality|glare|dark|bright|lighting/i.test(message);
8190
8217
  const isExpiredDoc = /document.*expired|expired.*document/i.test(message);
8191
8218
  const isFaceMatch = /face.*match|selfie.*match|does not match/i.test(message);
8192
- const errorIcon = isCameraErr ? "\xF0\u0178\u201C\xB7" : isNetworkErr ? "\xF0\u0178\u201C\xA1" : isAuthErr ? "\xE2\x8F\xB1" : isDocQuality ? "\xF0\u0178\u201D\x8D" : isExpiredDoc ? "\xF0\u0178\u201C\u2026" : isFaceMatch ? "\xF0\u0178\xA4\xB3" : "\xE2\u0153\u2022";
8219
+ const errorIcon = isCameraErr ? "📷" : isNetworkErr ? "📡" : isAuthErr ? "⏱" : isDocQuality ? "🔍" : isExpiredDoc ? "📅" : isFaceMatch ? "🤳" : "✕";
8193
8220
  const errorTitle = isCameraErr ? "Camera Access Required" : isNetworkErr ? "Connection Problem" : isAuthErr ? "Session Expired" : isDocQuality ? "Document Photo Unclear" : isExpiredDoc ? "Document Expired" : isFaceMatch ? "Face Match Failed" : "Verification Unsuccessful";
8194
8221
  const userMessage = isCameraErr ? "Please allow camera access in your browser settings and try again." : isNetworkErr ? "Check your internet connection and try again." : isAuthErr ? "Your session has expired. Please start again." : isDocQuality ? _sanitizeUserMessage(message) || "Please retake your document photo in good lighting with no glare." : isExpiredDoc ? "The document you submitted has expired. Please use a valid, current ID." : isFaceMatch ? "Your selfie did not match the photo on your ID. Please ensure you are using your own valid document and face the camera directly." : _sanitizeUserMessage(message) || "We were unable to complete your verification. Please try again.";
8195
8222
  const iconWrap = document.createElement("div");
@@ -8294,7 +8321,7 @@ var SmartComplySDK = (() => {
8294
8321
  stepIndicator.appendChild(this.stepLabel);
8295
8322
  header.appendChild(stepIndicator);
8296
8323
  const closeBtn = document.createElement("button");
8297
- closeBtn.innerHTML = "\xE2\u0153\u2022";
8324
+ closeBtn.innerHTML = "✕";
8298
8325
  closeBtn.setAttribute("aria-label", "Close identity verification");
8299
8326
  closeBtn.style.cssText = `
8300
8327
  width:32px;height:32px;border-radius:8px;flex-shrink:0;
@@ -8375,7 +8402,7 @@ var SmartComplySDK = (() => {
8375
8402
  }
8376
8403
  const arrow = document.createElement("span");
8377
8404
  arrow.style.cssText = `color:${this.theme.textMuted};font-size:18px;flex-shrink:0;`;
8378
- arrow.textContent = "\xE2\u2020\u2019";
8405
+ arrow.textContent = "→";
8379
8406
  card.appendChild(textWrap);
8380
8407
  card.appendChild(arrow);
8381
8408
  return card;
@@ -8447,7 +8474,7 @@ var SmartComplySDK = (() => {
8447
8474
  if (this.currentStep === "loading" || this.currentStep === "welcome") {
8448
8475
  this.stepLabel.textContent = "";
8449
8476
  } else if (this.currentStep === "done" || this.currentStep === "result") {
8450
- this.stepLabel.textContent = "Complete \xE2\u0153\u201C";
8477
+ this.stepLabel.textContent = "Complete ✓";
8451
8478
  } else if (stage2Steps.includes(this.currentStep)) {
8452
8479
  this.stepLabel.textContent = "Stage 2 of 2: Face Check";
8453
8480
  } else if (stage1Steps.includes(this.currentStep)) {
@@ -8561,20 +8588,20 @@ var SmartComplySDK = (() => {
8561
8588
  /** Emit an informational message (debug mode only). */
8562
8589
  info(message, ...args) {
8563
8590
  if (!isDebugEnabled()) return;
8564
- console.info(`${PREFIX} \u2139 ${message}`, ...args);
8591
+ console.info(`${PREFIX} ℹ ${message}`, ...args);
8565
8592
  },
8566
8593
  /** Emit a warning (always visible). */
8567
8594
  warn(message, ...args) {
8568
- console.warn(`${PREFIX} \u26A0 ${message}`, ...args);
8595
+ console.warn(`${PREFIX} ⚠ ${message}`, ...args);
8569
8596
  },
8570
8597
  /** Emit an error (always visible). */
8571
8598
  error(message, ...args) {
8572
- console.error(`${PREFIX} \u2716 ${message}`, ...args);
8599
+ console.error(`${PREFIX} ✖ ${message}`, ...args);
8573
8600
  },
8574
8601
  /** Emit a debug trace (debug mode only — lowest priority). */
8575
8602
  debug(message, ...args) {
8576
8603
  if (!isDebugEnabled()) return;
8577
- console.debug(`${PREFIX} \u2B21 ${message}`, ...args);
8604
+ console.debug(`${PREFIX} ⬡ ${message}`, ...args);
8578
8605
  },
8579
8606
  /** Log a timed group of related messages (debug mode only). */
8580
8607
  group(label, fn2) {
@@ -8732,7 +8759,7 @@ var SmartComplySDK = (() => {
8732
8759
  }
8733
8760
  };
8734
8761
  xhr.onerror = async () => {
8735
- SDKLogger.warn(`Upload to ${path} failed \u2014 network error`, { retriesLeft });
8762
+ SDKLogger.warn(`Upload to ${path} failed — network error`, { retriesLeft });
8736
8763
  if (retriesLeft > 0) {
8737
8764
  await new Promise((r2) => setTimeout(r2, RETRY_DELAY_MS));
8738
8765
  try {