@incodetech/prizma-core-screens 0.2.7 → 0.2.12

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 (168) hide show
  1. package/dist/BiometricConsentScreen.d.ts +95 -0
  2. package/dist/BiometricConsentScreen.js +91 -0
  3. package/dist/BiometricConsentStrings.d.ts +84 -0
  4. package/dist/BiometricConsentStrings.js +31 -0
  5. package/dist/CaptureScreen.d.ts +13 -0
  6. package/dist/CaptureScreen.js +2 -2
  7. package/dist/DemoScreensLayout.css +16 -0
  8. package/dist/DemoScreensRedirectScreen.d.ts +6 -1
  9. package/dist/DemoScreensRedirectScreen.js +3 -2
  10. package/dist/DemoScreensStrings.d.ts +5 -0
  11. package/dist/DigitalIdUploadErrorScreen.d.ts +31 -0
  12. package/dist/DigitalIdUploadErrorScreen.js +26 -0
  13. package/dist/DigitalIdUploadFileTooLargeScreen.d.ts +27 -0
  14. package/dist/DigitalIdUploadFileTooLargeScreen.js +21 -0
  15. package/dist/DigitalIdUploadReviewScreen.d.ts +57 -0
  16. package/dist/DigitalIdUploadReviewScreen.js +44 -0
  17. package/dist/DigitalIdUploadStrings.d.ts +64 -0
  18. package/dist/DigitalIdUploadStrings.js +19 -0
  19. package/dist/DigitalIdUploadTutorialScreen.d.ts +28 -0
  20. package/dist/DigitalIdUploadTutorialScreen.js +23 -0
  21. package/dist/DocumentCaptureIllustration.d.ts +1 -1
  22. package/dist/EkybCountryScreen.d.ts +6 -6
  23. package/dist/EkybCountryScreen.js +20 -7
  24. package/dist/EkybStrings.d.ts +6 -1
  25. package/dist/ErrorScreensScreen.d.ts +5 -2
  26. package/dist/ErrorScreensScreen.js +15 -4
  27. package/dist/ErrorScreensStrings.d.ts +17 -2
  28. package/dist/ErrorScreensStrings.js +18 -10
  29. package/dist/FaceCaptureCapturingScreen.d.ts +63 -0
  30. package/dist/FaceCaptureCapturingScreen.js +62 -2
  31. package/dist/FaceCaptureLayout.css +69 -4
  32. package/dist/FaceCaptureStrings.d.ts +23 -0
  33. package/dist/FormScreen.css +14 -0
  34. package/dist/FormScreen.d.ts +28 -0
  35. package/dist/FormScreen.js +3 -2
  36. package/dist/IdCaptureLayout.css +165 -2
  37. package/dist/IdCaptureStageScreen.d.ts +47 -0
  38. package/dist/IdCaptureStageScreen.js +39 -3
  39. package/dist/IdCaptureStrings.d.ts +19 -0
  40. package/dist/ListScreen.d.ts +19 -0
  41. package/dist/ListScreen.js +7 -2
  42. package/dist/LoaderScreen.d.ts +7 -5
  43. package/dist/LoaderScreen.js +7 -5
  44. package/dist/LoadersStrings.d.ts +18 -5
  45. package/dist/OcrReviewErrorScreen.d.ts +30 -0
  46. package/dist/OcrReviewErrorScreen.js +24 -0
  47. package/dist/OcrReviewLayout.css +24 -0
  48. package/dist/OcrReviewLoadingScreen.d.ts +25 -0
  49. package/dist/OcrReviewLoadingScreen.js +19 -0
  50. package/dist/OcrReviewScreen.d.ts +76 -0
  51. package/dist/OcrReviewScreen.js +65 -0
  52. package/dist/OcrReviewStrings.d.ts +47 -0
  53. package/dist/OcrReviewStrings.js +17 -0
  54. package/dist/OcrReviewSuccessScreen.d.ts +30 -0
  55. package/dist/OcrReviewSuccessScreen.js +24 -0
  56. package/dist/PermissionsAllowScreen.d.ts +8 -11
  57. package/dist/PermissionsAllowScreen.js +8 -11
  58. package/dist/PermissionsAskScreen.d.ts +41 -0
  59. package/dist/PermissionsAskScreen.js +43 -0
  60. package/dist/PermissionsBrowserStepsScreen.d.ts +9 -2
  61. package/dist/PermissionsBrowserStepsScreen.js +12 -3
  62. package/dist/PermissionsLayout.css +47 -0
  63. package/dist/PermissionsStrings.d.ts +20 -9
  64. package/dist/PermissionsStrings.js +10 -4
  65. package/dist/PhoneInputOtpScreen.d.ts +8 -0
  66. package/dist/PhoneInputOtpScreen.js +26 -19
  67. package/dist/PhoneInputStrings.d.ts +11 -3
  68. package/dist/PhoneInputVerifyScreen.js +21 -5
  69. package/dist/QualifiedSignatureDocumentScreen.d.ts +8 -5
  70. package/dist/QualifiedSignatureDocumentScreen.js +9 -6
  71. package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
  72. package/dist/QualifiedSignatureResultScreen.js +17 -18
  73. package/dist/QualifiedSignatureStrings.d.ts +11 -4
  74. package/dist/ResultScreen.d.ts +8 -0
  75. package/dist/ResultScreen.js +14 -3
  76. package/dist/ReusabilityCredentialSelectionScreen.d.ts +95 -0
  77. package/dist/ReusabilityCredentialSelectionScreen.js +94 -0
  78. package/dist/ReusabilityLayout.css +241 -0
  79. package/dist/ReusabilityPrivacyPolicyScreen.d.ts +55 -0
  80. package/dist/ReusabilityPrivacyPolicyScreen.js +44 -0
  81. package/dist/ReusabilityStrings.d.ts +85 -0
  82. package/dist/ReusabilityStrings.js +37 -0
  83. package/dist/ReviewScreen.d.ts +38 -12
  84. package/dist/ReviewScreen.js +41 -8
  85. package/dist/ScreenLayout.css +382 -6
  86. package/dist/VideoSelfieErrorScreen.js +1 -1
  87. package/dist/VideoSelfieIdCaptureScreen.js +1 -1
  88. package/dist/VideoSelfieLayout.css +304 -2
  89. package/dist/VideoSelfieSelfieCaptureScreen.js +1 -1
  90. package/dist/VideoSelfieSpeakScreen.js +1 -1
  91. package/dist/VideoSelfieStrings.d.ts +4 -1
  92. package/dist/VideoSelfieTurnHeadScreen.js +14 -11
  93. package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
  94. package/dist/VideoSelfieTutorialScreen.js +10 -1
  95. package/dist/VideoSelfieWaveScreen.js +1 -1
  96. package/dist/ViewfinderScreen.css +36 -0
  97. package/dist/flows.d.ts +8 -0
  98. package/dist/flows.js +17 -0
  99. package/dist/index.d.ts +16 -0
  100. package/dist/index.js +12 -0
  101. package/dist/styles.css +3 -0
  102. package/package.json +68 -3
  103. package/samples/video-selfie-camera-wide.jpg +0 -0
  104. package/samples/video-selfie-room-wide.jpg +0 -0
  105. package/src/BiometricConsentScreen.tsx +192 -0
  106. package/src/BiometricConsentStrings.ts +119 -0
  107. package/src/CaptureScreen.tsx +17 -0
  108. package/src/DemoScreensLayout.css +16 -0
  109. package/src/DemoScreensRedirectScreen.tsx +14 -6
  110. package/src/DemoScreensStrings.ts +5 -0
  111. package/src/DigitalIdUploadErrorScreen.tsx +83 -0
  112. package/src/DigitalIdUploadFileTooLargeScreen.tsx +67 -0
  113. package/src/DigitalIdUploadReviewScreen.tsx +119 -0
  114. package/src/DigitalIdUploadStrings.ts +88 -0
  115. package/src/DigitalIdUploadTutorialScreen.tsx +59 -0
  116. package/src/DocumentCaptureIllustration.tsx +1 -1
  117. package/src/EkybCountryScreen.tsx +23 -6
  118. package/src/EkybStrings.ts +6 -1
  119. package/src/ErrorScreensScreen.tsx +15 -4
  120. package/src/ErrorScreensStrings.ts +37 -12
  121. package/src/FaceCaptureCapturingScreen.tsx +102 -13
  122. package/src/FaceCaptureLayout.css +69 -4
  123. package/src/FaceCaptureStrings.ts +24 -0
  124. package/src/FormScreen.css +14 -0
  125. package/src/FormScreen.tsx +34 -0
  126. package/src/IdCaptureLayout.css +165 -2
  127. package/src/IdCaptureStageScreen.tsx +75 -0
  128. package/src/IdCaptureStrings.ts +19 -0
  129. package/src/ListScreen.tsx +48 -9
  130. package/src/LoaderScreen.tsx +7 -5
  131. package/src/LoadersStrings.ts +18 -5
  132. package/src/OcrReviewErrorScreen.tsx +53 -0
  133. package/src/OcrReviewLayout.css +24 -0
  134. package/src/OcrReviewLoadingScreen.tsx +48 -0
  135. package/src/OcrReviewScreen.tsx +190 -0
  136. package/src/OcrReviewStrings.ts +69 -0
  137. package/src/OcrReviewSuccessScreen.tsx +52 -0
  138. package/src/PermissionsAllowScreen.tsx +9 -10
  139. package/src/PermissionsAskScreen.tsx +105 -0
  140. package/src/PermissionsBrowserStepsScreen.tsx +11 -3
  141. package/src/PermissionsLayout.css +47 -0
  142. package/src/PermissionsStrings.ts +42 -12
  143. package/src/PhoneInputOtpScreen.tsx +23 -3
  144. package/src/PhoneInputStrings.ts +11 -3
  145. package/src/PhoneInputVerifyScreen.tsx +24 -4
  146. package/src/QualifiedSignatureDocumentScreen.tsx +9 -7
  147. package/src/QualifiedSignatureResultScreen.tsx +28 -26
  148. package/src/QualifiedSignatureStrings.ts +11 -4
  149. package/src/ResultScreen.tsx +33 -2
  150. package/src/ReusabilityCredentialSelectionScreen.tsx +246 -0
  151. package/src/ReusabilityLayout.css +241 -0
  152. package/src/ReusabilityPrivacyPolicyScreen.tsx +109 -0
  153. package/src/ReusabilityStrings.ts +127 -0
  154. package/src/ReviewScreen.tsx +96 -27
  155. package/src/ScreenLayout.css +382 -6
  156. package/src/VideoSelfieErrorScreen.tsx +1 -1
  157. package/src/VideoSelfieIdCaptureScreen.tsx +9 -1
  158. package/src/VideoSelfieLayout.css +304 -2
  159. package/src/VideoSelfieSelfieCaptureScreen.tsx +9 -1
  160. package/src/VideoSelfieSpeakScreen.tsx +9 -1
  161. package/src/VideoSelfieStrings.ts +4 -2
  162. package/src/VideoSelfieTurnHeadScreen.tsx +25 -14
  163. package/src/VideoSelfieTutorialScreen.tsx +11 -0
  164. package/src/VideoSelfieWaveScreen.tsx +9 -1
  165. package/src/ViewfinderScreen.css +36 -0
  166. package/src/flows.ts +25 -0
  167. package/src/index.ts +74 -3
  168. package/src/styles.css +3 -0
@@ -13,6 +13,14 @@
13
13
  * spoken step) carry the band here.
14
14
  */
15
15
 
16
+ /* The air above the stepper band, named once because TWO rules depend on it:
17
+ * the band's own offset and the ring's, which counts down from Figma's y=188.
18
+ * Scoped to a shell that actually carries the band, so no other module's
19
+ * screen inherits a property it never reads. */
20
+ .prizma-screen-shell:has(> .video-selfie-stepper) {
21
+ --vs-top-reserve: max(var(--pcs-status-bar, 47px), var(--prizma-spacing-24));
22
+ }
23
+
16
24
  /* ── Journey stepper band ────────────────────────────────────────────────────
17
25
  * Figma draws the Stepper as the first thing under the OS status bar — no logo
18
26
  * row above it (`top content` frame, y=54, the Stepper 342 wide at x=24 on
@@ -42,7 +50,14 @@
42
50
  * ScreenLayout.css already reserves for the tag and shutter, which must sit
43
51
  * above the scrim for exactly the same reason. DEVIATIONS #VS-2. */
44
52
  z-index: 2;
45
- margin-top: var(--pcs-status-bar, 47px);
53
+ /* Clear the OS status bar, and NEVER sit flush against the top edge. A host
54
+ * that draws no phone chrome sets `--pcs-status-bar: 0px` — Core Lab's
55
+ * desktop panel does — and the band then started at pixel zero, hard against
56
+ * the browser bar (Camila, 2026-10-09: "the stepper is way too high and
57
+ * touches the screen border"). The floor is the content column's own
58
+ * Spacing/24 gutter, the same air every other screen has above its first
59
+ * block; on a phone the 47 reserve is larger and nothing moves. */
60
+ margin-top: var(--vs-top-reserve, var(--pcs-status-bar, 47px));
46
61
  padding-inline: var(--prizma-spacing-24);
47
62
  }
48
63
 
@@ -63,6 +78,74 @@
63
78
  z-index: 1;
64
79
  }
65
80
 
81
+ /* A band carrying the coaching bubble keeps the bubble's own height; the frame
82
+ * below is what gives ground on a short screen.
83
+ *
84
+ * `.video-selfie-band` is `flex: 1; min-height: 0`, so on a 360 × 640 panel the
85
+ * flex column took the whole shortfall out of THIS band: it collapsed to zero
86
+ * and the bubble — which is still painted — overflowed it in both directions,
87
+ * across the stepper above and the document frame below (Camila, 2026-10-07).
88
+ * `IdCaptureLayout.css` already names the rule for this exact column: the frame
89
+ * is the one part that shrinks, the band above it keeps its content height. Same
90
+ * rule, this module's class. */
91
+ .video-selfie-band:has(> .video-selfie-feedback) {
92
+ flex: 0 0 auto;
93
+ min-height: min-content;
94
+ }
95
+
96
+ /* …and the band UNDER the document stage never gives up the footer's own
97
+ * footprint, so the frame stops above the verified tag instead of sliding under
98
+ * it. `ScreenLayout.css` reserves `--pcs-footer-space` on
99
+ * `.prizma-screen-layout__content`; these are camera surfaces with no content
100
+ * column, so the reserve has to be claimed here, and claiming it as the BAND's
101
+ * minimum rather than as padding on the viewfinder is what keeps the reference
102
+ * untouched: at 390 the band is already ~100 tall, so a 72 floor is a no-op and
103
+ * the frame stays exactly where Figma centres it (y 172–627 of a 91–708 content
104
+ * area). On a 640-tall panel the floor binds, and the frame — the one part of
105
+ * this column that may get smaller (owner, 2026-08-18) — gives the height back
106
+ * through Core's own `flex-basis`, its aspect narrowing it to match. */
107
+ .video-selfie-stage + .video-selfie-band {
108
+ min-height: var(--pcs-footer-space);
109
+ }
110
+
111
+ /* ── The camera owns the window; only the HUD is a column ────────────────────
112
+ * The five camera screens carry `data-pcs-overlay="window"` on their shell.
113
+ * That attribute is the screens package's contract with a host that FRAMES a
114
+ * screen — Core Lab's desktop panel, which otherwise lays every screen inside
115
+ * the 800 x 840 white card Elena's eKYB frames draw. A form belongs in that
116
+ * card. A camera does not: boxed into it, the feed and its scrim were a narrow
117
+ * strip with white either side of them on a 1440 panel, the desktop version of
118
+ * the "phone pasted onto the tablet" her 2026-10-02 call already fixed for the
119
+ * tablet (Camila, 2026-10-08). `PermissionsAskScreen` set the same attribute
120
+ * first, for its dialog's dim.
121
+ *
122
+ * NOT fixed here: Face Capture's, ID Capture's and Document Capture's camera
123
+ * stages sit in the same card for the same reason. The rule reads as theirs
124
+ * too, but their screens have not been looked at on the panel — reported. */
125
+
126
+ /* ── The HUD stays in a column when the panel is wider than the reference ─────
127
+ * On a panel wider than 390 the camera feed and its scrim are full-bleed — that
128
+ * is what a camera does on a real device, and what the Lab's laid-out
129
+ * breakpoints draw (`bleed`, convert.ts). The copy over the feed is NOT: left to
130
+ * `width: 100%` the stepper ran the full 720 of a tablet and the coaching bubble
131
+ * with it, which reads as a stretched phone rather than a tablet (Camila,
132
+ * 2026-10-07).
133
+ *
134
+ * `--pcs-column` is the host's own property for this — the same contract as
135
+ * `--pcs-status-bar` — and it is already what `ScreenLayout`'s content and band
136
+ * read on a device panel: 390 on a phone, 468 on a tablet or desktop one. Here
137
+ * the two Spacing/24 gutters come off it, because these bands sit INSIDE
138
+ * `.prizma-viewfinder__content`'s own padding, so the result is exactly the
139
+ * content width the reference has (342 at 390, 420 on a tablet). Unset — a plain
140
+ * 390 screen, any SDK host — the calc resolves to 342 and nothing moves. */
141
+ .video-selfie-stepper > *,
142
+ .video-selfie-feedback,
143
+ .video-selfie-recording,
144
+ .video-selfie-turn {
145
+ max-width: calc(var(--pcs-column, 390px) - 2 * var(--prizma-spacing-24));
146
+ margin-inline: auto;
147
+ }
148
+
66
149
  /* ── The face ring sits in the SAME place on every screen ────────────────────
67
150
  * Figma puts `ring-uploading` at (27, 188) on every frame that draws it —
68
151
  * `8.x`, `9.x`, the four head turns and the wave — and never moves it. Left
@@ -81,7 +164,95 @@
81
164
  * DEVIATIONS #VS-24. */
82
165
  .video-selfie-band--ring {
83
166
  justify-content: flex-start;
84
- padding-top: calc(188px - var(--pcs-status-bar, 47px) - 37px - var(--prizma-spacing-40));
167
+ /* 188 is Figma's, and on a panel SHORTER than the 844 the frames are drawn
168
+ * against it is read proportionally: 154 at 693, 143 at 640. The reference
169
+ * and anything taller keep the literal 188, which is what `min()` guarantees.
170
+ * Fixed, it was 29% of a 640 panel — the ring plus its status block ran up to
171
+ * 67px past the fold (Camila, 2026-10-07), and the air above a ring is the
172
+ * first thing that should give. */
173
+ padding-top: max(
174
+ 0px,
175
+ calc(
176
+ min(188px, 100cqh * 188 / 844) - var(--vs-top-reserve, var(--pcs-status-bar, 47px)) -
177
+ 37px - var(--prizma-spacing-40)
178
+ )
179
+ );
180
+ }
181
+
182
+ /* ── On a LANDSCAPE window the ring centres instead ──────────────────────────
183
+ * 188 is a portrait measurement: it is 22% down an 844 phone, and the capture
184
+ * block reads as sitting near the top with the instruction under it. Down a
185
+ * 1440 x 820 browser window the same offset leaves the whole bottom half empty
186
+ * and the composition reads as a phone screen pinned to the top of a desktop
187
+ * page (Camila, 2026-10-09).
188
+ *
189
+ * #VS-24's rule survives intact, and it is the reason this is an OFFSET and not
190
+ * `justify-content: center`. The rule is that the ring does not move BETWEEN
191
+ * screens — a capture window that jumps as the step advances reads as a glitch
192
+ * — and the stack under the ring is a different height on every one of them (an
193
+ * instruction here, a spinner and a label there, an arrow chip on the turns).
194
+ * Centring that stack would move the ring again, which is the exact bug #VS-24
195
+ * was written for. Centring the RING instead depends on two numbers only: the
196
+ * shell's height and Core's own 335 capture box. Every ring screen lands in the
197
+ * same place, and the copy flows below it as before. */
198
+ @container pcs-screen (min-aspect-ratio: 1 / 1) {
199
+ .video-selfie-band--ring {
200
+ padding-top: max(
201
+ 0px,
202
+ calc(
203
+ (100cqh - 335px) / 2 - var(--vs-top-reserve, var(--pcs-status-bar, 47px)) - 37px -
204
+ var(--prizma-spacing-40)
205
+ )
206
+ );
207
+ }
208
+ }
209
+
210
+ /* ── …and on a short panel the ring itself gives ground ──────────────────────
211
+ * Scaling the offset is not enough at 640: the stack below the ring is a title
212
+ * and a subtitle on the verdict beats ("Selfie not captured, try again") and an
213
+ * arrow plus an instruction on the turns, and all of it is content height the
214
+ * band cannot take back.
215
+ *
216
+ * So the RING shrinks, exactly the way `IdCaptureLayout.css` already lets the
217
+ * document frame shrink and for the same stated reason — the capture window may
218
+ * get smaller, that is not a constraint (owner, 2026-08-18). Core's stage is
219
+ * `width: 100%; aspect-ratio: 1`, so giving it a flex basis of its own width and
220
+ * letting the column take the shortfall out of its HEIGHT makes the aspect
221
+ * narrow it back: still a circle, still centred, just smaller. Everything inside
222
+ * it is already proportional (the ring is an SVG on a 335 viewBox, the
223
+ * silhouette is in %), so nothing else has to be told.
224
+ *
225
+ * 87.7cqw is Core's own capture width (`min(87.7cqw, 335px)` — 335 of the 390
226
+ * reference); it is named here only because a flex basis cannot read it off the
227
+ * element it is sizing. Outside the query not one of these declarations exists,
228
+ * so the reference stage is untouched. */
229
+ @container pcs-screen (max-height: 720px) {
230
+ .prizma-viewfinder__content:has(> .video-selfie-band--ring) {
231
+ min-height: 0;
232
+ }
233
+
234
+ .video-selfie-band--ring {
235
+ min-height: 0;
236
+ }
237
+
238
+ .video-selfie-band--ring > .prizma-selfie-capture {
239
+ flex: 0 1 auto;
240
+ min-height: 0;
241
+ }
242
+
243
+ .video-selfie-band--ring .prizma-selfie-capture__stage {
244
+ flex: 0 1 auto;
245
+ min-height: 0;
246
+ width: auto;
247
+ max-width: 100%;
248
+ flex-basis: min(335px, 87.7cqw);
249
+ }
250
+
251
+ /* The copy under the ring keeps its own height — the ring is what shrinks. */
252
+ .video-selfie-band--ring > .prizma-selfie-capture > :not(.prizma-selfie-capture__stage),
253
+ .video-selfie-band--ring > .video-selfie-turn {
254
+ flex-shrink: 0;
255
+ }
85
256
  }
86
257
 
87
258
  /* ── Recording indicator (10.1 / 11.1 / 11.3 / 11.5) ─────────────────────────
@@ -117,6 +288,20 @@
117
288
  bottom: 0;
118
289
  z-index: 3;
119
290
  padding: var(--prizma-spacing-16);
291
+ /* The SCRIM is full-bleed; the card is not. On a panel wider than the
292
+ * reference the panel keeps the host's column (`--pcs-column`, see the HUD
293
+ * block above) and centres, so the card stays a card instead of a 720-wide
294
+ * strip. Its own Spacing/16 inset is untouched, which is what keeps the
295
+ * reference rendering byte-identical: at 390 the column IS the panel. */
296
+ max-width: var(--pcs-column, none);
297
+ margin-inline: auto;
298
+ }
299
+
300
+ /* Core's Modal caps itself too, so on a tablet's 468 column the card has room
301
+ * to spare inside the panel and was landing flush left. Centre it, same as the
302
+ * coaching bubble. */
303
+ .video-selfie-sheet-panel > * {
304
+ margin-inline: auto;
120
305
  }
121
306
 
122
307
  /* The confirmation dialog (10.4) is a true centred modal over a dimmed screen,
@@ -173,6 +358,36 @@
173
358
  height: var(--prizma-title-icon-size);
174
359
  }
175
360
 
361
+ /* ── The tutorial's seven rows on a short panel ──────────────────────────────
362
+ * The promise list fits the 844 reference to the pixel — measured 497 of the
363
+ * 497 the column leaves — so on a 693 or 640 panel the last two rows painted
364
+ * through the CTA and the verified tag (Camila, 2026-10-07).
365
+ *
366
+ * The concession is the one archetype G already ships and this module already
367
+ * uses on its Android settings walk-through: the ROWS pan, the title, the CTA
368
+ * band and the anchored tag hold still (`__list--scroll`, ScreenLayout.css).
369
+ * It is applied here, under a container query, rather than through the
370
+ * `scrollList` prop, because that variant also adds a Spacing/16 margin below
371
+ * the list — on the reference that is 16 of the 497 the rows need, so the prop
372
+ * would start clipping the very screen it is meant to leave alone.
373
+ *
374
+ * 720 is the same line the live cues use: the reference is 844, and anything
375
+ * at 640 or 693 is a short panel. */
376
+ @container pcs-screen (max-height: 720px) {
377
+ .video-selfie-tutorial .prizma-screen-layout__list {
378
+ overflow-y: auto;
379
+ /* `__list--scroll`'s own Spacing/16, so the row the clip cuts through is not
380
+ flush against the CTA. Inside the query it costs the reference nothing. */
381
+ margin-bottom: var(--prizma-spacing-16);
382
+ }
383
+
384
+ /* Rows keep their intrinsic height instead of being squeezed — the reason
385
+ `__list--scroll` carries the same declaration. */
386
+ .video-selfie-tutorial .prizma-screen-layout__list > * {
387
+ flex-shrink: 0;
388
+ }
389
+ }
390
+
176
391
  /* ── The OS settings walk-through (2.5) ──────────────────────────────────────
177
392
  * Two labelled sections inside archetype G's list slot: a numbered step list
178
393
  * and a plain note. CONTENT typography only — the offset above the block is
@@ -348,6 +563,82 @@
348
563
  margin-block: 0 auto;
349
564
  }
350
565
 
566
+ /* Core caps the pill itself at 400 (CaptureFeedback.css, FLAG-DOUBLE-MAXWIDTH),
567
+ * which is narrower than a tablet's 420 column — so inside the wrapper it has
568
+ * 20px to spare and was landing flush left, off the frame's centre line. Same
569
+ * centring `.video-selfie-stage` needs, for the same reason. */
570
+ .video-selfie-feedback > .prizma-capture-feedback {
571
+ margin-inline: auto;
572
+ }
573
+
574
+ /* ── The live cues go COMPACT on a small phone ───────────────────────────────
575
+ * `PrizmaCaptureFeedback` ships two templates on its own `Show Animation` axis:
576
+ * A, the 135px pill with the illustration beside the copy at Headline/H3, and
577
+ * B, a 72px pill with no illustration at Headline/H5 (CaptureFeedback.css,
578
+ * "Compact modifier"). The module's frames draw A, and A is what every screen
579
+ * with room keeps.
580
+ *
581
+ * It is the wrong template on a small phone. At 320 the pill's 70px
582
+ * illustration column plus its Spacing/16 gap take 86 of the 272 the content
583
+ * has — a third of the width spent on a decoration — so "Center your ID inside
584
+ * the frame" wrapped to three lines and the pill grew to 150; on the 640-tall
585
+ * panel the same pill is a quarter of the whole screen. Either way it ate the
586
+ * air the document frame needs, and the frame came down through it (Camila,
587
+ * 2026-10-07: "in smaller phones, the live cues should change to the compact
588
+ * version"). Template B says the same two lines in 72.
589
+ *
590
+ * A CONTAINER query, and in the SCREENS layer rather than CaptureFeedback.css,
591
+ * for the reason `ScreenLayout.css` gives on the capture notice: Core web
592
+ * components are width-agnostic by design, and the browser viewport is not the
593
+ * phone — in Core Lab a 320 shell sits inside a 1400px window, so `@media`
594
+ * would read the wrong number. `pcs-screen` is the shell's own container
595
+ * (ScreenShell.css).
596
+ *
597
+ * Two triggers, because two different things run out:
598
+ * · 340 wide — the line above the narrowest phone we support and below the
599
+ * next one, the same threshold the capture notice drops its glyph at: 320
600
+ * goes compact, 360 and 390 keep the illustration.
601
+ * · 720 tall — the reference is 844 and the frames are drawn against it. A
602
+ * panel at 640 or 693 has no air to spend on a 135px pill, however wide it
603
+ * is. 720 clears 844, 932 and the tablet's 1024.
604
+ *
605
+ * Nothing is re-skinned: the pill's fill, radius, stroke and shadow are Core's
606
+ * and identical between A and B (capture-feedback.md §4.4). What changes is
607
+ * exactly Template B's four switches. DEVIATIONS #VS-30. */
608
+ /* ⚠ ONE `or` condition, not two comma-separated queries. A container query
609
+ * names its container ONCE and the conditions go in a single boolean group:
610
+ * `pcs-screen (a), pcs-screen (b)` parses in Chrome and is a hard error in
611
+ * lightningcss, so the hub's production build failed on it while the dev server
612
+ * was fine. Any future multi-condition query in this package wants this shape. */
613
+ @container pcs-screen ((max-width: 340px) or (max-height: 720px)) {
614
+ .video-selfie-feedback .prizma-capture-feedback__illustration {
615
+ display: none;
616
+ }
617
+
618
+ /* Template B: body padding-bottom 12 → 16, itemSpacing 8 → 4. */
619
+ .video-selfie-feedback .prizma-capture-feedback__body {
620
+ padding: var(--prizma-spacing-16) 0;
621
+ gap: var(--prizma-spacing-4);
622
+ }
623
+
624
+ /* Title Headline/H3 → Headline/H5. */
625
+ .video-selfie-feedback .prizma-capture-feedback__title {
626
+ font-weight: var(--prizma-headline-h5-font-weight);
627
+ font-size: var(--prizma-headline-h5-font-size);
628
+ line-height: var(--prizma-headline-h5-line-height);
629
+ letter-spacing: var(--prizma-headline-h5-letter-spacing);
630
+ }
631
+
632
+ /* Subtitle Headline/H5 → Body/M Regular. */
633
+ .video-selfie-feedback .prizma-capture-feedback__subtitle {
634
+ font-family: var(--prizma-body-family);
635
+ font-weight: var(--prizma-body-m-regular-font-weight);
636
+ font-size: var(--prizma-body-m-regular-font-size);
637
+ line-height: var(--prizma-body-m-regular-line-height);
638
+ letter-spacing: var(--prizma-body-m-regular-letter-spacing);
639
+ }
640
+ }
641
+
351
642
  /* ── The head-turn mark and its instruction ──────────────────────────────────
352
643
  * The `🙂‍↔️ Turn Head` band puts a 48 circled arrow between the ring and the
353
644
  * line that says which way to turn (`element container` 342×48, the glyph
@@ -375,6 +666,17 @@
375
666
  color: var(--prizma-icon-neutral-50-static);
376
667
  }
377
668
 
669
+ /* The mark NEVER mirrors in a right-to-left locale (owner decision, Sofia
670
+ * 2026-10-07). A head turn is a physical direction, not a reading direction,
671
+ * so "left" stays left in Hebrew too. Core flips the horizontal chevrons in
672
+ * RTL through `[dir="rtl"] .prizma-icon--rtl-mirror` (Navigation.css); this
673
+ * rule, the same selector scoped to the mark, outranks it on this screen only
674
+ * and every other chevron keeps mirroring. The solid circle arrows the mark
675
+ * used to be never flipped, so this restores their behaviour. */
676
+ [dir='rtl'] .video-selfie-turn__mark .prizma-icon--rtl-mirror {
677
+ transform: none;
678
+ }
679
+
378
680
  /* Step rows — the <ol> `PrizmaList` would supply, composed here only because
379
681
  * the wrapper has no variant reaching Core's plain `number` squircle (#VS-16).
380
682
  * The gap is the icon family's own Spacing/12; nothing new is declared. */
@@ -69,7 +69,7 @@ export const VideoSelfieSelfieCaptureScreen = forwardRef(({ strings, state = 'st
69
69
  carry Core's own status copy instead (its `statusLabels` slot), which is
70
70
  why the feedback line is scoped to the live state. */
71
71
  const feedbackText = state === 'start' ? (feedback ? slice.feedback[feedback] : slice.startLabel) : undefined;
72
- return (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: STEP, documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
72
+ return (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, "data-pcs-overlay": "window", className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: STEP, documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
73
73
  'prizma-viewfinder__content',
74
74
  overrides?.align === 'left' ? 'prizma-viewfinder__content--left' : '',
75
75
  ]
@@ -93,7 +93,7 @@ export const VideoSelfieSpeakScreen = forwardRef(({ strings, family = 'voiceCons
93
93
  secondaryLabel: slice.idleCtaLabel,
94
94
  onSecondaryClick: () => onAction?.({ type: 'cta', screenId }),
95
95
  } }));
96
- return (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: STEP[family], documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
96
+ return (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, "data-pcs-overlay": "window", className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: STEP[family], documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
97
97
  'prizma-viewfinder__content',
98
98
  overrides?.align === 'left' ? 'prizma-viewfinder__content--left' : '',
99
99
  ]
@@ -252,9 +252,12 @@ export interface VideoSelfieStrings {
252
252
  ctaLabel: string;
253
253
  quitLabel: string;
254
254
  };
255
- /** `14.4` — connectivity. */
255
+ /** `14.4` — connectivity. The supporting line is the generic family's
256
+ * (`ErrorScreensStrings.noConnection.subtitle`), so this screen reads
257
+ * like every other module's connectivity screen (#F-34, #PI-8). */
256
258
  noConnection: {
257
259
  title: string;
260
+ subtitle?: string;
258
261
  ctaLabel: string;
259
262
  quitLabel: string;
260
263
  };
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { forwardRef } from 'react';
4
- import { IconArrowDownCircle, IconArrowLeftCircle, IconArrowRightCircle, IconArrowUpCircle, } from '@incodetech/prizma-core-icons';
4
+ import { IconChevronDown, IconChevronLeft, IconChevronRight, IconChevronUp, } from '@incodetech/prizma-core-icons';
5
5
  import { PrizmaSelfieCapture } from '@incodetech/prizma-core-web/selfie-capture';
6
6
  import { PrizmaStepper } from '@incodetech/prizma-core-web/stepper';
7
7
  import { PrizmaScreenShell } from './ScreenShell';
@@ -12,17 +12,20 @@ import './VideoSelfieLayout.css';
12
12
  * Direction → the mark under the ring, from the canonical bank at 2xl (48) —
13
13
  * the size the frames draw it (`element container` 342×48, the glyph centred).
14
14
  *
15
- * It is ONE glyph, a filled disc with the arrow knocked out of it, which is
16
- * what `Left Circle - Iconly Pro` is. The first pass paired a 24px bare arrow
17
- * with a hand-made disc behind it and read as a thin chevron floating on the
18
- * camera (owner, 2026-09-30). The four circle arrows were extracted into the
19
- * bank on the same day. Nothing is drawn here (§10).
15
+ * Since the Core and Enterprise icon unification (Sofia, 2026-10-06) the
16
+ * mark is the library chevron at 2xl: the four solid circle arrows left the
17
+ * bank (their old names now alias the chevrons). Nothing is drawn here (§10).
18
+ *
19
+ * The mark never mirrors in RTL (Sofia, 2026-10-07): a head turn is a
20
+ * physical direction, so the chevrons keep their LTR orientation in Hebrew.
21
+ * The opt-out is one scoped rule in `VideoSelfieLayout.css`; the chevrons
22
+ * still mirror everywhere else.
20
23
  */
21
24
  const TURN_ICON = {
22
- left: _jsx(IconArrowLeftCircle, { size: "2xl" }),
23
- right: _jsx(IconArrowRightCircle, { size: "2xl" }),
24
- up: _jsx(IconArrowUpCircle, { size: "2xl" }),
25
- down: _jsx(IconArrowDownCircle, { size: "2xl" }),
25
+ left: _jsx(IconChevronLeft, { size: "2xl" }),
26
+ right: _jsx(IconChevronRight, { size: "2xl" }),
27
+ up: _jsx(IconChevronUp, { size: "2xl" }),
28
+ down: _jsx(IconChevronDown, { size: "2xl" }),
26
29
  };
27
30
  /**
28
31
  * Video Selfie — the head-turn beats of the liveness sequence (Archetype D,
@@ -47,7 +50,7 @@ const TURN_ICON = {
47
50
  * `glyph` slot on the capture stage, so this and Face Capture's future hint
48
51
  * marks share one component. DEVIATIONS #VS-20.
49
52
  */
50
- export const VideoSelfieTurnHeadScreen = forwardRef(({ strings, direction = 'left', stage = 'ask', documentType = 'id', camera, screenId = `video-selfie-turn-${direction}-${stage}`, overrides, onAction, className, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: 4, documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
53
+ export const VideoSelfieTurnHeadScreen = forwardRef(({ strings, direction = 'left', stage = 'ask', documentType = 'id', camera, screenId = `video-selfie-turn-${direction}-${stage}`, overrides, onAction, className, ...shell }, ref) => (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, "data-pcs-overlay": "window", className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: 4, documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
51
54
  'prizma-viewfinder__content',
52
55
  overrides?.align === 'left' ? 'prizma-viewfinder__content--left' : '',
53
56
  ]
@@ -3,6 +3,7 @@ import { type PrizmaListScreenProps } from './ListScreen';
3
3
  import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
4
4
  import type { VideoSelfieDocumentType, VideoSelfieStrings } from './VideoSelfieStrings';
5
5
  import './ScreenLayout.css';
6
+ import './VideoSelfieLayout.css';
6
7
  export interface VideoSelfieTutorialScreenProps extends Omit<PrizmaListScreenProps, 'status' | 'title' | 'subtitle' | 'children' | 'ctaLabel' | 'secondaryCtaLabel' | 'linkLabel' | 'verifiedLabel' | 'navLabel'> {
7
8
  /** Module copy — this screen reads the `tutorial` slice. */
8
9
  strings: VideoSelfieStrings;
@@ -28,6 +29,14 @@ export interface VideoSelfieTutorialScreenProps extends Omit<PrizmaListScreenPro
28
29
  * NOT archetype A: A centres one illustration in the flexible middle; here the
29
30
  * middle is a seven-row list that must span the column and start at the top —
30
31
  * the distinction `ScreenLayout.css` draws between `__flex` and `__list`.
32
+ *
33
+ * The one class it carries, `video-selfie-tutorial`, exists so the module's
34
+ * stylesheet can reach this screen on a SHORT panel: seven rows fit the 844
35
+ * reference to the pixel (measured 497 of 497), and on a 640 or 693 one they
36
+ * paint straight through the CTA. `VideoSelfieLayout.css` lets them pan there,
37
+ * the same concession the Android settings walk-through already makes with
38
+ * `scrollList` — and `scrollList` itself is not used here because its
39
+ * Spacing/16 margin would take the reference below the 497 the rows need.
31
40
  */
32
41
  export declare const VideoSelfieTutorialScreen: React.ForwardRefExoticComponent<VideoSelfieTutorialScreenProps & React.RefAttributes<HTMLDivElement>>;
33
42
  export default VideoSelfieTutorialScreen;
@@ -5,6 +5,7 @@ import { IconBankCard, IconMessages, IconMicrophone, IconNumberedList, IconPassp
5
5
  import { PrizmaList } from '@incodetech/prizma-core-web/list';
6
6
  import { PrizmaListScreen } from './ListScreen';
7
7
  import './ScreenLayout.css';
8
+ import './VideoSelfieLayout.css';
8
9
  /**
9
10
  * Journey beat → canonical bank glyph. ONE map, in one place — the same seven
10
11
  * glyphs Core's `PrizmaStepper` carries (its icon set is documented as "the
@@ -39,8 +40,16 @@ const ROW_ICONS = {
39
40
  * NOT archetype A: A centres one illustration in the flexible middle; here the
40
41
  * middle is a seven-row list that must span the column and start at the top —
41
42
  * the distinction `ScreenLayout.css` draws between `__flex` and `__list`.
43
+ *
44
+ * The one class it carries, `video-selfie-tutorial`, exists so the module's
45
+ * stylesheet can reach this screen on a SHORT panel: seven rows fit the 844
46
+ * reference to the pixel (measured 497 of 497), and on a 640 or 693 one they
47
+ * paint straight through the CTA. `VideoSelfieLayout.css` lets them pan there,
48
+ * the same concession the Android settings walk-through already makes with
49
+ * `scrollList` — and `scrollList` itself is not used here because its
50
+ * Spacing/16 margin would take the reference below the 497 the rows need.
42
51
  */
43
- export const VideoSelfieTutorialScreen = forwardRef(({ strings, documentType = 'id', screenId = `video-selfie-tutorial-${documentType}`, overrides, onAction, ...shell }, ref) => (_jsx(PrizmaListScreen, { ref: ref, title: strings.tutorial.title, subtitle: strings.tutorial.subtitle, ctaLabel: strings.tutorial.ctaLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaList, { variant: "icons-chain", showItem3: true, showItem4: true, showItem5: true, showItem6: true, showItem7: true, items: strings.tutorial.rows[documentType].map((row) => ({
52
+ export const VideoSelfieTutorialScreen = forwardRef(({ strings, documentType = 'id', screenId = `video-selfie-tutorial-${documentType}`, overrides, onAction, className, ...shell }, ref) => (_jsx(PrizmaListScreen, { ref: ref, className: ['video-selfie-tutorial', className].filter(Boolean).join(' '), title: strings.tutorial.title, subtitle: strings.tutorial.subtitle, ctaLabel: strings.tutorial.ctaLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx(PrizmaList, { variant: "icons-chain", showItem3: true, showItem4: true, showItem5: true, showItem6: true, showItem7: true, items: strings.tutorial.rows[documentType].map((row) => ({
44
53
  variant: 'icon-connector',
45
54
  label: row.label,
46
55
  icon: ROW_ICONS[row.kind],
@@ -39,7 +39,7 @@ import './VideoSelfieLayout.css';
39
39
  export const VideoSelfieWaveScreen = forwardRef(({ strings, stage = 'waiting', documentType = 'id', camera, screenId = `video-selfie-wave-${stage}`, overrides, onAction, className, ...shell }, ref) => {
40
40
  const slice = strings.selfieCapture.wave;
41
41
  const seen = stage === 'success';
42
- return (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: 5, documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
42
+ return (_jsxs(PrizmaScreenShell, { ref: ref, dark: true, "data-pcs-overlay": "window", className: className, ...shell, children: [_jsx("div", { className: "prizma-viewfinder__surface", children: camera }), _jsx("div", { className: "video-selfie-stepper", children: _jsx(PrizmaStepper, { steps: 7, currentState: 5, documentType: documentType, completedValueText: strings.stepperCompletedLabel }) }), _jsx("div", { className: [
43
43
  'prizma-viewfinder__content',
44
44
  overrides?.align === 'left' ? 'prizma-viewfinder__content--left' : '',
45
45
  ]
@@ -13,6 +13,42 @@
13
13
  object-fit: cover;
14
14
  }
15
15
 
16
+ /* ── A feed has an ASPECT, and the plate has to match it ─────────────────────
17
+ * `object-fit: cover` is right for a live feed and wrong for a still: a phone
18
+ * plate is 390 x 844, and covering a 1440 x 820 browser window scales it 3.7x,
19
+ * so the subject fills the window and her face lands nowhere near the capture
20
+ * ring (Camila, 2026-10-09: "the image is now too zoomed in because full screen
21
+ * is not good for this image ratio"). A real desktop webcam does not hand the
22
+ * page a portrait frame; it hands it a landscape one.
23
+ *
24
+ * So the HOST may supply two plates and the viewfinder picks the one whose
25
+ * shape fits the shell it is actually being drawn at:
26
+ *
27
+ * <div className="prizma-viewfinder__surface">
28
+ * <img data-pcs-plate="tall" src={portrait} alt="" />
29
+ * <img data-pcs-plate="wide" src={landscape} alt="" />
30
+ * </div>
31
+ *
32
+ * Supply one and nothing changes — an untagged `<img>` or `<video>` is shown at
33
+ * every shape, which is every existing caller. A CONTAINER query, not a media
34
+ * one, for the reason `ScreenLayout.css` gives on the capture notice: the
35
+ * browser viewport is not the screen, and in Core Lab a 390 shell sits inside a
36
+ * 1400px window. The line is square: anything wider than it is tall takes the
37
+ * landscape plate. */
38
+ .prizma-viewfinder__surface > [data-pcs-plate='wide'] {
39
+ display: none;
40
+ }
41
+
42
+ @container pcs-screen (min-aspect-ratio: 1 / 1) {
43
+ .prizma-viewfinder__surface > [data-pcs-plate='tall'] {
44
+ display: none;
45
+ }
46
+
47
+ .prizma-viewfinder__surface > [data-pcs-plate='wide'] {
48
+ display: block;
49
+ }
50
+ }
51
+
16
52
  .prizma-viewfinder__content {
17
53
  position: relative;
18
54
  z-index: 1;
package/dist/flows.d.ts CHANGED
@@ -20,6 +20,10 @@ export interface FaceCaptureFlowVariant {
20
20
  ctaLoading?: boolean;
21
21
  /** FaceCaptureCapturingScreen — which of the 15 `capturing.*` sections. */
22
22
  state?: FaceCaptureCapturingState;
23
+ /** FaceCaptureCapturingScreen — raise the "Need more time?" offer over the
24
+ * feed. A modifier of `state`, not one of the fifteen: the fallback timer
25
+ * runs underneath whichever guidance is showing. */
26
+ extendTime?: boolean;
23
27
  /** FaceCaptureLoadingScreen — `loading.uploading` vs `loading.processing`. */
24
28
  stage?: 'uploading' | 'processing';
25
29
  /** FaceCaptureResultErrorScreen — the `*Exhausted` half of the error pairs. */
@@ -167,6 +171,10 @@ export interface IdCaptureFlowVariant {
167
171
  vertical?: boolean;
168
172
  /** IdCaptureStageScreen — which stage section. */
169
173
  state?: IdCaptureStageState;
174
+ /** IdCaptureStageScreen — raise the "Need more time?" offer over the feed.
175
+ * A modifier of `state`, not one of the eleven: the fallback timer runs
176
+ * underneath whichever stage is showing. */
177
+ extendTime?: boolean;
170
178
  /** IdCaptureStageScreen — the `*-manual` sections. */
171
179
  manual?: boolean;
172
180
  /** IdCaptureResultScreen — which verdict section. */
package/dist/flows.js CHANGED
@@ -79,6 +79,14 @@ export const faceCaptureFlow = [
79
79
  /** The off-path screens: manual capture (offered when auto-capture is turned
80
80
  * off or gives up), the two error verdicts, and the connectivity error. */
81
81
  export const faceCaptureBranches = [
82
+ {
83
+ // A branch, not a step: it only appears when accessibility mode is ON for
84
+ // the flow AND the fallback timer is 20 s from expiring. It returns to the
85
+ // capturing states it came from, so it never "follows" anything.
86
+ screenId: 'face-capture-capturing-extend-time',
87
+ component: FaceCaptureCapturingScreen,
88
+ variant: { state: 'alignFace', extendTime: true },
89
+ },
82
90
  {
83
91
  screenId: 'face-capture-manual-capture',
84
92
  component: FaceCaptureManualCaptureScreen,
@@ -442,6 +450,15 @@ export const idCaptureBranches = [
442
450
  screenId: 'id-capture-age-verification',
443
451
  component: IdCaptureAgeVerificationScreen,
444
452
  },
453
+ {
454
+ // A branch, not a step: it only appears when accessibility mode is ON for
455
+ // the flow AND the 30 s fallback timer is 20 s from expiring. It returns
456
+ // to the hint stage it came from, so it never "follows" anything — the
457
+ // same shape as Face Capture's `capturing-extend-time`.
458
+ screenId: 'id-capture-front-extend-time',
459
+ component: IdCaptureStageScreen,
460
+ variant: { state: 'hint', extendTime: true },
461
+ },
445
462
  {
446
463
  screenId: 'id-capture-front-manual',
447
464
  component: IdCaptureStageScreen,
package/dist/index.d.ts CHANGED
@@ -33,6 +33,11 @@ export { DocumentCaptureConfirmImageScreen, type DocumentCaptureConfirmImageScre
33
33
  export { DocumentCaptureConfirmUploadScreen, type DocumentCaptureConfirmUploadScreenProps, } from './DocumentCaptureConfirmUploadScreen';
34
34
  export { DocumentCaptureGenericErrorScreen, type DocumentCaptureGenericErrorScreenProps, } from './DocumentCaptureGenericErrorScreen';
35
35
  export { DocumentCaptureNoConnectionScreen, type DocumentCaptureNoConnectionScreenProps, } from './DocumentCaptureNoConnectionScreen';
36
+ export { type DigitalIdUploadStrings, type DigitalIdUploadConfirmStage, } from './DigitalIdUploadStrings';
37
+ export { DigitalIdUploadTutorialScreen, type DigitalIdUploadTutorialScreenProps, } from './DigitalIdUploadTutorialScreen';
38
+ export { DigitalIdUploadReviewScreen, type DigitalIdUploadReviewScreenProps, } from './DigitalIdUploadReviewScreen';
39
+ export { DigitalIdUploadErrorScreen, type DigitalIdUploadErrorScreenProps, } from './DigitalIdUploadErrorScreen';
40
+ export { DigitalIdUploadFileTooLargeScreen, type DigitalIdUploadFileTooLargeScreenProps, } from './DigitalIdUploadFileTooLargeScreen';
36
41
  export { type IdCaptureStrings, type IdCaptureDocumentType, type IdCaptureSide, type IdCaptureStageState, type IdCaptureFeedbackKind, type IdCaptureFeedbackCopy, type IdCaptureListRow, } from './IdCaptureStrings';
37
42
  export { IdCaptureDocumentSelectionScreen, type IdCaptureDocumentSelectionScreenProps, } from './IdCaptureDocumentSelectionScreen';
38
43
  export { IdCaptureAgeVerificationScreen, type IdCaptureAgeVerificationScreenProps, } from './IdCaptureAgeVerificationScreen';
@@ -89,6 +94,11 @@ export { FormsLongFormScreen, type FormsLongFormScreenProps } from './FormsLongF
89
94
  export { FormsSuccessScreen, type FormsSuccessScreenProps } from './FormsSuccessScreen';
90
95
  export { type DataSharingConsentState, type DataSharingConsentItemStrings, type DataSharingConsentStrings, } from './DataSharingConsentStrings';
91
96
  export { DataSharingConsentConsentScreen, type DataSharingConsentConsentScreenProps } from './DataSharingConsentConsentScreen';
97
+ export { type BiometricConsentState, type BiometricConsentStrings, } from './BiometricConsentStrings';
98
+ export { BiometricConsentScreen, type BiometricConsentScreenProps } from './BiometricConsentScreen';
99
+ export { type ReusabilityDocumentType, type ReusableCredential, type ReusabilityStrings, } from './ReusabilityStrings';
100
+ export { ReusabilityCredentialSelectionScreen, REUSABILITY_SCAN_NEW, type ReusabilitySelection, type ReusabilityCredentialSelectionScreenProps, } from './ReusabilityCredentialSelectionScreen';
101
+ export { ReusabilityPrivacyPolicyScreen, type ReusabilityPrivacyPolicyScreenProps } from './ReusabilityPrivacyPolicyScreen';
92
102
  export { type EkycDetailsState, type EkycLicenseState, type EkycLicenseStateOption, type EkycDetailsValues, type EkycLicenseValues, type EkycStrings, type EkycCountryValues, } from './EkycStrings';
93
103
  export { EKYC_COUNTRY_CATALOG, ekycCountryVariant, type EkycCountryVariant, type EkycCountryStep, type EkycField, type EkycFieldKey, type EkycFieldKind, } from './EkycCountryCatalog';
94
104
  export { EkycCountryFormScreen, type EkycCountryFormScreenProps } from './EkycCountryFormScreen';
@@ -135,7 +145,13 @@ export { NfcSuccessScreen, type NfcSuccessScreenProps } from './NfcSuccessScreen
135
145
  export { NfcSymbolScreen, type NfcSymbolScreenProps } from './NfcSymbolScreen';
136
146
  export { NfcTryAgainScreen, type NfcTryAgainStep, type NfcTryAgainScreenProps, } from './NfcTryAgainScreen';
137
147
  export { NfcTutorialScreen, type NfcTutorialScreenProps } from './NfcTutorialScreen';
148
+ export { type OcrReviewState, type OcrReviewStrings, } from './OcrReviewStrings';
149
+ export { OcrReviewScreen, type OcrReviewScreenProps } from './OcrReviewScreen';
150
+ export { OcrReviewLoadingScreen, type OcrReviewLoadingScreenProps } from './OcrReviewLoadingScreen';
151
+ export { OcrReviewSuccessScreen, type OcrReviewSuccessScreenProps } from './OcrReviewSuccessScreen';
152
+ export { OcrReviewErrorScreen, type OcrReviewErrorScreenProps } from './OcrReviewErrorScreen';
138
153
  export { type PermissionsStrings, type PermissionsCapability, type PermissionsReasonRow, type PermissionsBrowser, type PermissionsStepKind, type PermissionsStep, type PermissionsBrowserSteps, } from './PermissionsStrings';
154
+ export { PermissionsAskScreen, type PermissionsAskScreenProps, } from './PermissionsAskScreen';
139
155
  export { PermissionsRequiredScreen, type PermissionsRequiredScreenProps, } from './PermissionsRequiredScreen';
140
156
  export { PermissionsAllowScreen, type PermissionsAllowScreenProps, } from './PermissionsAllowScreen';
141
157
  export { PermissionsBrowserStepsScreen, type PermissionsBrowserStepsScreenProps, } from './PermissionsBrowserStepsScreen';