@incodetech/prizma-core-screens 0.2.4 → 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 (243) 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/CurpEnterScreen.d.ts +7 -0
  8. package/dist/CurpEnterScreen.js +17 -3
  9. package/dist/CurpGenerateScreen.d.ts +8 -0
  10. package/dist/CurpGenerateScreen.js +28 -13
  11. package/dist/CurpLayout.css +8 -34
  12. package/dist/CurpStrings.d.ts +16 -2
  13. package/dist/DemoScreensLayout.css +16 -0
  14. package/dist/DemoScreensRedirectScreen.d.ts +6 -1
  15. package/dist/DemoScreensRedirectScreen.js +3 -2
  16. package/dist/DemoScreensStrings.d.ts +5 -0
  17. package/dist/DigitalIdUploadErrorScreen.d.ts +31 -0
  18. package/dist/DigitalIdUploadErrorScreen.js +26 -0
  19. package/dist/DigitalIdUploadFileTooLargeScreen.d.ts +27 -0
  20. package/dist/DigitalIdUploadFileTooLargeScreen.js +21 -0
  21. package/dist/DigitalIdUploadReviewScreen.d.ts +57 -0
  22. package/dist/DigitalIdUploadReviewScreen.js +44 -0
  23. package/dist/DigitalIdUploadStrings.d.ts +64 -0
  24. package/dist/DigitalIdUploadStrings.js +19 -0
  25. package/dist/DigitalIdUploadTutorialScreen.d.ts +28 -0
  26. package/dist/DigitalIdUploadTutorialScreen.js +23 -0
  27. package/dist/DocumentCaptureIllustration.d.ts +1 -1
  28. package/dist/EkybAddressDetailsScreen.d.ts +7 -0
  29. package/dist/EkybAddressDetailsScreen.js +25 -7
  30. package/dist/EkybBusinessDetailsScreen.d.ts +6 -0
  31. package/dist/EkybBusinessDetailsScreen.js +23 -6
  32. package/dist/EkybCountryScreen.d.ts +13 -5
  33. package/dist/EkybCountryScreen.js +41 -10
  34. package/dist/EkybOwnersScreen.d.ts +8 -0
  35. package/dist/EkybOwnersScreen.js +26 -3
  36. package/dist/EkybStrings.d.ts +32 -10
  37. package/dist/EkycCountryCatalog.d.ts +4 -1
  38. package/dist/EkycCountryCatalog.js +5 -3
  39. package/dist/EkycCountryFormScreen.d.ts +12 -3
  40. package/dist/EkycCountryFormScreen.js +28 -10
  41. package/dist/EkycDetailsScreen.d.ts +7 -0
  42. package/dist/EkycDetailsScreen.js +21 -4
  43. package/dist/EkycStrings.d.ts +14 -2
  44. package/dist/ElectronicSignatureLayout.css +6 -0
  45. package/dist/EmailInputStrings.d.ts +11 -1
  46. package/dist/EmailInputVerifyScreen.d.ts +7 -0
  47. package/dist/EmailInputVerifyScreen.js +17 -3
  48. package/dist/ErrorScreensScreen.d.ts +5 -2
  49. package/dist/ErrorScreensScreen.js +15 -4
  50. package/dist/ErrorScreensStrings.d.ts +17 -2
  51. package/dist/ErrorScreensStrings.js +18 -10
  52. package/dist/FaceCaptureCapturingScreen.d.ts +63 -0
  53. package/dist/FaceCaptureCapturingScreen.js +62 -2
  54. package/dist/FaceCaptureLayout.css +69 -4
  55. package/dist/FaceCaptureStrings.d.ts +23 -0
  56. package/dist/FaceMatchComparisonScreen.d.ts +3 -3
  57. package/dist/FaceMatchLayout.css +21 -12
  58. package/dist/FormScreen.css +30 -0
  59. package/dist/FormScreen.d.ts +28 -0
  60. package/dist/FormScreen.js +3 -2
  61. package/dist/FormsLongFormScreen.d.ts +8 -0
  62. package/dist/FormsLongFormScreen.js +34 -13
  63. package/dist/FormsStrings.d.ts +11 -1
  64. package/dist/GeolocationBrowserStepsScreen.d.ts +6 -2
  65. package/dist/GeolocationBrowserStepsScreen.js +7 -3
  66. package/dist/GeolocationStrings.d.ts +3 -0
  67. package/dist/IdCaptureLayout.css +205 -2
  68. package/dist/IdCaptureStageScreen.d.ts +47 -0
  69. package/dist/IdCaptureStageScreen.js +39 -3
  70. package/dist/IdCaptureStrings.d.ts +19 -0
  71. package/dist/ListScreen.d.ts +21 -0
  72. package/dist/ListScreen.js +7 -2
  73. package/dist/LoaderScreen.d.ts +7 -5
  74. package/dist/LoaderScreen.js +7 -5
  75. package/dist/LoadersStrings.d.ts +18 -5
  76. package/dist/OcrReviewErrorScreen.d.ts +30 -0
  77. package/dist/OcrReviewErrorScreen.js +24 -0
  78. package/dist/OcrReviewLayout.css +24 -0
  79. package/dist/OcrReviewLoadingScreen.d.ts +25 -0
  80. package/dist/OcrReviewLoadingScreen.js +19 -0
  81. package/dist/OcrReviewScreen.d.ts +76 -0
  82. package/dist/OcrReviewScreen.js +65 -0
  83. package/dist/OcrReviewStrings.d.ts +47 -0
  84. package/dist/OcrReviewStrings.js +17 -0
  85. package/dist/OcrReviewSuccessScreen.d.ts +30 -0
  86. package/dist/OcrReviewSuccessScreen.js +24 -0
  87. package/dist/PermissionsAllowScreen.d.ts +8 -11
  88. package/dist/PermissionsAllowScreen.js +8 -11
  89. package/dist/PermissionsAskScreen.d.ts +41 -0
  90. package/dist/PermissionsAskScreen.js +43 -0
  91. package/dist/PermissionsBrowserStepsScreen.d.ts +9 -2
  92. package/dist/PermissionsBrowserStepsScreen.js +12 -3
  93. package/dist/PermissionsLayout.css +47 -0
  94. package/dist/PermissionsStrings.d.ts +20 -9
  95. package/dist/PermissionsStrings.js +10 -4
  96. package/dist/PhoneInputLayout.css +10 -9
  97. package/dist/PhoneInputOtpScreen.d.ts +8 -0
  98. package/dist/PhoneInputOtpScreen.js +26 -19
  99. package/dist/PhoneInputStrings.d.ts +22 -4
  100. package/dist/PhoneInputVerifyScreen.d.ts +8 -0
  101. package/dist/PhoneInputVerifyScreen.js +36 -7
  102. package/dist/QualifiedSignatureAcceptScreen.js +6 -1
  103. package/dist/QualifiedSignatureDocumentScreen.d.ts +17 -10
  104. package/dist/QualifiedSignatureDocumentScreen.js +22 -17
  105. package/dist/QualifiedSignatureLayout.css +76 -0
  106. package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
  107. package/dist/QualifiedSignatureResultScreen.js +17 -18
  108. package/dist/QualifiedSignatureStrings.d.ts +19 -2
  109. package/dist/ResultScreen.d.ts +8 -0
  110. package/dist/ResultScreen.js +14 -3
  111. package/dist/ReusabilityCredentialSelectionScreen.d.ts +95 -0
  112. package/dist/ReusabilityCredentialSelectionScreen.js +94 -0
  113. package/dist/ReusabilityLayout.css +241 -0
  114. package/dist/ReusabilityPrivacyPolicyScreen.d.ts +55 -0
  115. package/dist/ReusabilityPrivacyPolicyScreen.js +44 -0
  116. package/dist/ReusabilityStrings.d.ts +85 -0
  117. package/dist/ReusabilityStrings.js +37 -0
  118. package/dist/ReviewScreen.d.ts +38 -12
  119. package/dist/ReviewScreen.js +41 -8
  120. package/dist/ScreenLayout.css +382 -6
  121. package/dist/ScreenNav.css +8 -0
  122. package/dist/ScreenNav.d.ts +15 -2
  123. package/dist/ScreenNav.js +10 -3
  124. package/dist/VideoSelfieErrorScreen.js +1 -1
  125. package/dist/VideoSelfieIdCaptureScreen.d.ts +10 -3
  126. package/dist/VideoSelfieIdCaptureScreen.js +45 -14
  127. package/dist/VideoSelfieLayout.css +467 -34
  128. package/dist/VideoSelfieSelfieCaptureScreen.d.ts +44 -27
  129. package/dist/VideoSelfieSelfieCaptureScreen.js +65 -39
  130. package/dist/VideoSelfieSpeakScreen.js +19 -2
  131. package/dist/VideoSelfieStrings.d.ts +82 -13
  132. package/dist/VideoSelfieTurnHeadScreen.d.ts +51 -0
  133. package/dist/VideoSelfieTurnHeadScreen.js +66 -0
  134. package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
  135. package/dist/VideoSelfieTutorialScreen.js +22 -5
  136. package/dist/VideoSelfieWaveScreen.d.ts +53 -0
  137. package/dist/VideoSelfieWaveScreen.js +62 -0
  138. package/dist/ViewfinderScreen.css +36 -0
  139. package/dist/WatchlistBusinessFormScreen.d.ts +11 -7
  140. package/dist/WatchlistBusinessFormScreen.js +27 -13
  141. package/dist/WatchlistBusinessStrings.d.ts +21 -7
  142. package/dist/flows.d.ts +8 -0
  143. package/dist/flows.js +17 -0
  144. package/dist/index.d.ts +19 -1
  145. package/dist/index.js +14 -0
  146. package/dist/styles.css +3 -0
  147. package/dist/types.d.ts +3 -1
  148. package/package.json +79 -3
  149. package/samples/video-selfie-camera-wide.jpg +0 -0
  150. package/samples/video-selfie-room-wide.jpg +0 -0
  151. package/samples/video-selfie-room.png +0 -0
  152. package/src/BiometricConsentScreen.tsx +192 -0
  153. package/src/BiometricConsentStrings.ts +119 -0
  154. package/src/CaptureScreen.tsx +17 -0
  155. package/src/CurpEnterScreen.tsx +21 -4
  156. package/src/CurpGenerateScreen.tsx +46 -22
  157. package/src/CurpLayout.css +8 -34
  158. package/src/CurpStrings.ts +22 -2
  159. package/src/DemoScreensLayout.css +16 -0
  160. package/src/DemoScreensRedirectScreen.tsx +14 -6
  161. package/src/DemoScreensStrings.ts +5 -0
  162. package/src/DigitalIdUploadErrorScreen.tsx +83 -0
  163. package/src/DigitalIdUploadFileTooLargeScreen.tsx +67 -0
  164. package/src/DigitalIdUploadReviewScreen.tsx +119 -0
  165. package/src/DigitalIdUploadStrings.ts +88 -0
  166. package/src/DigitalIdUploadTutorialScreen.tsx +59 -0
  167. package/src/DocumentCaptureIllustration.tsx +1 -1
  168. package/src/EkybAddressDetailsScreen.tsx +32 -4
  169. package/src/EkybBusinessDetailsScreen.tsx +23 -5
  170. package/src/EkybCountryScreen.tsx +45 -7
  171. package/src/EkybOwnersScreen.tsx +34 -3
  172. package/src/EkybStrings.ts +34 -10
  173. package/src/EkycCountryCatalog.ts +9 -4
  174. package/src/EkycCountryFormScreen.tsx +51 -12
  175. package/src/EkycDetailsScreen.tsx +22 -1
  176. package/src/EkycStrings.ts +14 -2
  177. package/src/ElectronicSignatureLayout.css +6 -0
  178. package/src/EmailInputStrings.ts +12 -1
  179. package/src/EmailInputVerifyScreen.tsx +21 -4
  180. package/src/ErrorScreensScreen.tsx +15 -4
  181. package/src/ErrorScreensStrings.ts +37 -12
  182. package/src/FaceCaptureCapturingScreen.tsx +102 -13
  183. package/src/FaceCaptureLayout.css +69 -4
  184. package/src/FaceCaptureStrings.ts +24 -0
  185. package/src/FaceMatchComparisonScreen.tsx +3 -3
  186. package/src/FaceMatchLayout.css +21 -12
  187. package/src/FormScreen.css +30 -0
  188. package/src/FormScreen.tsx +34 -0
  189. package/src/FormsLongFormScreen.tsx +41 -13
  190. package/src/FormsStrings.ts +12 -1
  191. package/src/GeolocationBrowserStepsScreen.tsx +6 -3
  192. package/src/GeolocationStrings.ts +3 -0
  193. package/src/IdCaptureLayout.css +205 -2
  194. package/src/IdCaptureStageScreen.tsx +75 -0
  195. package/src/IdCaptureStrings.ts +19 -0
  196. package/src/ListScreen.tsx +58 -10
  197. package/src/LoaderScreen.tsx +7 -5
  198. package/src/LoadersStrings.ts +18 -5
  199. package/src/OcrReviewErrorScreen.tsx +53 -0
  200. package/src/OcrReviewLayout.css +24 -0
  201. package/src/OcrReviewLoadingScreen.tsx +48 -0
  202. package/src/OcrReviewScreen.tsx +190 -0
  203. package/src/OcrReviewStrings.ts +69 -0
  204. package/src/OcrReviewSuccessScreen.tsx +52 -0
  205. package/src/PermissionsAllowScreen.tsx +9 -10
  206. package/src/PermissionsAskScreen.tsx +105 -0
  207. package/src/PermissionsBrowserStepsScreen.tsx +11 -3
  208. package/src/PermissionsLayout.css +47 -0
  209. package/src/PermissionsStrings.ts +42 -12
  210. package/src/PhoneInputLayout.css +10 -9
  211. package/src/PhoneInputOtpScreen.tsx +23 -3
  212. package/src/PhoneInputStrings.ts +23 -4
  213. package/src/PhoneInputVerifyScreen.tsx +41 -5
  214. package/src/QualifiedSignatureAcceptScreen.tsx +12 -1
  215. package/src/QualifiedSignatureDocumentScreen.tsx +31 -19
  216. package/src/QualifiedSignatureLayout.css +76 -0
  217. package/src/QualifiedSignatureResultScreen.tsx +28 -26
  218. package/src/QualifiedSignatureStrings.ts +19 -2
  219. package/src/ResultScreen.tsx +33 -2
  220. package/src/ReusabilityCredentialSelectionScreen.tsx +246 -0
  221. package/src/ReusabilityLayout.css +241 -0
  222. package/src/ReusabilityPrivacyPolicyScreen.tsx +109 -0
  223. package/src/ReusabilityStrings.ts +127 -0
  224. package/src/ReviewScreen.tsx +96 -27
  225. package/src/ScreenLayout.css +382 -6
  226. package/src/ScreenNav.css +8 -0
  227. package/src/ScreenNav.tsx +35 -5
  228. package/src/VideoSelfieErrorScreen.tsx +1 -1
  229. package/src/VideoSelfieIdCaptureScreen.tsx +125 -31
  230. package/src/VideoSelfieLayout.css +467 -34
  231. package/src/VideoSelfieSelfieCaptureScreen.tsx +110 -57
  232. package/src/VideoSelfieSpeakScreen.tsx +34 -15
  233. package/src/VideoSelfieStrings.ts +89 -14
  234. package/src/VideoSelfieTurnHeadScreen.tsx +162 -0
  235. package/src/VideoSelfieTutorialScreen.tsx +45 -23
  236. package/src/VideoSelfieWaveScreen.tsx +143 -0
  237. package/src/ViewfinderScreen.css +36 -0
  238. package/src/WatchlistBusinessFormScreen.tsx +35 -16
  239. package/src/WatchlistBusinessStrings.ts +21 -7
  240. package/src/flows.ts +25 -0
  241. package/src/index.ts +88 -3
  242. package/src/styles.css +3 -0
  243. package/src/types.ts +3 -1
@@ -0,0 +1,241 @@
1
+ /* Reusability (Incode Bridge) — module layout additions.
2
+ *
3
+ * Three recipes, every value a Prizma token: the credential rows the selection
4
+ * screen lists, the bullet list inside the shared-details sheet, and the framed
5
+ * reader the privacy policy scrolls in. The content column, the 24px gutters,
6
+ * the title → list offset, the CTA band, the sheet scrim and panel and the
7
+ * anchored footer are all the foundation's (`ScreenLayout.css`); the sheet
8
+ * itself, the buttons, the title and the flag raster are Core's.
9
+ *
10
+ * WHY THE ROWS ARE COMPOSED HERE. The frame names the list "Verification
11
+ * options card list", but it is not Core's `Card / Verification options item`
12
+ * (60px card icon + title + chevron): each row is a document-type label with a
13
+ * status pill, the masked number behind a flag, and the date it was verified —
14
+ * and the last row is a single line with a pill. Core ships no card with that
15
+ * anatomy and no plain status pill (its `PrizmaCardTag` is the ⚡ Instant pill,
16
+ * with the glyph baked in). Both are built below from Core's own tokens — no
17
+ * palette, no radius, no spacing invented — and both are logged as component
18
+ * proposals (DEVIATIONS #RU-1, #RU-2). The moment Core ships them, these rules
19
+ * go and the screen imports the component.
20
+ */
21
+
22
+ /* ── The credential list ─────────────────────────────────────────────────────
23
+ * Two bordered containers, Spacing/16 apart (`options`, 7877:68823): the
24
+ * reusable documents in the first, "Scan a new document" alone in the second.
25
+ * Rows inside a container touch, each drawing a top hairline the way Core's
26
+ * verification-options rows do (`Card.css`); the container clips the corners. */
27
+ .reusability-credentials {
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: var(--prizma-spacing-16);
31
+ width: 100%;
32
+ }
33
+
34
+ .reusability-credentials__group {
35
+ display: flex;
36
+ flex-direction: column;
37
+ overflow: hidden;
38
+ box-sizing: border-box;
39
+ width: 100%;
40
+ background-color: var(--prizma-surface-neutral-0);
41
+ border: var(--prizma-border-width-regular) solid var(--prizma-border-neutral-100);
42
+ border-radius: var(--prizma-border-radius-medium);
43
+ }
44
+
45
+ /* The row IS the action — a real <button>, one tap advances (consent review
46
+ * 2026-09-16: "remove the confirm button"). Button reset, then the frame's
47
+ * Spacing/16 padding and Spacing/8 between its lines. */
48
+ .reusability-credential {
49
+ display: flex;
50
+ flex-direction: column;
51
+ align-items: stretch;
52
+ gap: var(--prizma-spacing-8);
53
+ box-sizing: border-box;
54
+ width: 100%;
55
+ margin: 0;
56
+ padding: var(--prizma-spacing-16);
57
+ background-color: var(--prizma-surface-neutral-0);
58
+ border: none;
59
+ border-top: var(--prizma-border-width-regular) solid var(--prizma-border-neutral-100);
60
+ color: var(--prizma-text-body-800-primary);
61
+ font-family: var(--prizma-body-family);
62
+ text-align: left;
63
+ cursor: pointer;
64
+ -webkit-font-smoothing: antialiased;
65
+ }
66
+
67
+ .reusability-credentials__group > .reusability-credential:first-child {
68
+ border-top: none;
69
+ }
70
+
71
+ /* Keyboard focus: Core's Button ring, so a row and the links below it light
72
+ * up the same way. Inset, because the group clips its corners. */
73
+ .reusability-credential:focus-visible {
74
+ outline: var(--prizma-button-focus-ring-width) solid var(--prizma-border-status-focus);
75
+ outline-offset: calc(-1 * var(--prizma-button-focus-ring-width));
76
+ }
77
+
78
+ /* Line 1: the document-type label, the pill at the far right. */
79
+ .reusability-credential__head {
80
+ display: flex;
81
+ align-items: center;
82
+ justify-content: space-between;
83
+ gap: var(--prizma-spacing-8);
84
+ width: 100%;
85
+ }
86
+
87
+ .reusability-credential__type {
88
+ margin: 0;
89
+ color: var(--prizma-text-body-800-primary);
90
+ font-family: var(--prizma-body-family);
91
+ font-size: var(--prizma-body-m-regular-font-size);
92
+ font-weight: var(--prizma-body-m-regular-font-weight);
93
+ line-height: var(--prizma-body-m-regular-line-height);
94
+ letter-spacing: var(--prizma-body-m-regular-letter-spacing);
95
+ }
96
+
97
+ /* Line 2: the flag and the masked number, Headline/H5. */
98
+ .reusability-credential__number {
99
+ display: flex;
100
+ align-items: center;
101
+ gap: var(--prizma-spacing-4);
102
+ margin: 0;
103
+ color: var(--prizma-text-body-800-primary);
104
+ font-family: var(--prizma-headline-family);
105
+ font-size: var(--prizma-headline-h5-font-size);
106
+ font-weight: var(--prizma-headline-h5-font-weight);
107
+ line-height: var(--prizma-headline-h5-line-height);
108
+ letter-spacing: var(--prizma-headline-h5-letter-spacing);
109
+ }
110
+
111
+ /* Core's flag raster is 24×18; the frame draws an emoji glyph at the text
112
+ * size. The raster wins (owner decision 2026-07-12: flags are images, never
113
+ * emoji) and keeps its own geometry — DEVIATIONS #RU-3. */
114
+ .reusability-credential__flag {
115
+ display: inline-flex;
116
+ flex: 0 0 auto;
117
+ align-items: center;
118
+ }
119
+
120
+ /* Line 3: "Verified Apr 2023", Body/M in the secondary ink. */
121
+ .reusability-credential__verified {
122
+ margin: 0;
123
+ color: var(--prizma-text-body-500-secondary);
124
+ font-family: var(--prizma-body-family);
125
+ font-size: var(--prizma-body-m-regular-font-size);
126
+ font-weight: var(--prizma-body-m-regular-font-weight);
127
+ line-height: var(--prizma-body-m-regular-line-height);
128
+ letter-spacing: var(--prizma-body-m-regular-letter-spacing);
129
+ }
130
+
131
+ /* ── The status pill ─────────────────────────────────────────────────────────
132
+ * "Recommended" on the best match, "Slowest" on the capture row. Surface/Brand/50
133
+ * for the first, inked with Card/Tag/Text — the mode-aware AA pair Core's own
134
+ * ⚡ pill uses (Brand.600 light · Focus.400 dark; owner call 2026-07-14), because
135
+ * the frame's Text/Accent/Brand on Brand/50 is blue on blue in dark mode;
136
+ * Surface/Neutral/50 with a Border/Neutral/200 hairline for the second — the
137
+ * frame's own fills. Radius x-small (4) and Spacing/2 × Spacing/4 padding, as
138
+ * drawn.
139
+ *
140
+ * TYPE: the frame sets the label in Body/S Regular (12px). Core's generated
141
+ * scale has no 12px text step — Body/M and Label/M are 14 — so the pill takes
142
+ * Label/M Regular, the smallest token the scale has. DEVIATIONS #RU-2. */
143
+ .reusability-pill {
144
+ display: inline-flex;
145
+ align-items: center;
146
+ flex: 0 0 auto;
147
+ padding: var(--prizma-spacing-2) var(--prizma-spacing-4);
148
+ border-radius: var(--prizma-border-radius-x-small);
149
+ font-family: var(--prizma-body-family);
150
+ font-size: var(--prizma-label-m-regular-font-size);
151
+ font-weight: var(--prizma-label-m-regular-font-weight);
152
+ line-height: var(--prizma-label-m-regular-line-height);
153
+ letter-spacing: var(--prizma-label-m-regular-letter-spacing);
154
+ white-space: nowrap;
155
+ }
156
+
157
+ .reusability-pill--recommended {
158
+ background-color: var(--prizma-surface-brand-50);
159
+ color: var(--prizma-card-tag-text);
160
+ }
161
+
162
+ .reusability-pill--neutral {
163
+ background-color: var(--prizma-surface-neutral-50);
164
+ border: var(--prizma-border-width-regular) solid var(--prizma-border-neutral-200);
165
+ color: var(--prizma-text-body-800-primary);
166
+ }
167
+
168
+ /* ── The shared-details list ─────────────────────────────────────────────────
169
+ * Inside Core's dialog sheet (`__body` slot): the recipient's data request as
170
+ * bullets, Headline/H5 in the primary ink, Spacing/8 apart, the browser's own
171
+ * disc marker on a Spacing/24 indent (`Documents list`, 7877:68985). Core's
172
+ * sheet supplies the Spacing/24 above it. */
173
+ .reusability-shared-list {
174
+ display: flex;
175
+ flex-direction: column;
176
+ gap: var(--prizma-spacing-8);
177
+ margin: 0;
178
+ padding: 0 0 0 var(--prizma-spacing-24);
179
+ color: var(--prizma-text-body-800-primary);
180
+ font-family: var(--prizma-headline-family);
181
+ font-size: var(--prizma-headline-h5-font-size);
182
+ font-weight: var(--prizma-headline-h5-font-weight);
183
+ line-height: var(--prizma-headline-h5-line-height);
184
+ letter-spacing: var(--prizma-headline-h5-letter-spacing);
185
+ text-align: left;
186
+ }
187
+
188
+ .reusability-shared-list > li {
189
+ margin: 0;
190
+ padding: 0;
191
+ }
192
+
193
+ /* ── The privacy-policy reader ───────────────────────────────────────────────
194
+ * The framed, scrolling document Qualified Signature's viewers draw
195
+ * (`.qualified-signature-document--framed`, DEVIATIONS #QS-n): a hairline
196
+ * frame on radius-small, Spacing/16 inside, Body/M prose with Spacing/12
197
+ * between paragraphs, the dateline first. The frame's `demo_5` draws the text
198
+ * unframed on a 32px gutter; the framed reader is what every document viewer
199
+ * in this package draws (owner call 2026-09-29, "take reference from other
200
+ * screens"), so it is followed here — DEVIATIONS #RU-7.
201
+ *
202
+ * FOUNDATION REQUEST: this is the SECOND module drawing the framed reader.
203
+ * Promote it to `ScreenLayout.css` as `__document` (the #DC-29 / #BC-8 idiom:
204
+ * the third consumer moves the recipe), and both module copies go. */
205
+ .reusability-document {
206
+ flex: 1 1 auto;
207
+ min-height: 0;
208
+ box-sizing: border-box;
209
+ width: 100%;
210
+ overflow-y: auto;
211
+ overscroll-behavior: contain;
212
+ padding: var(--prizma-spacing-16);
213
+ margin-bottom: var(--prizma-spacing-16);
214
+ background-color: var(--prizma-surface-neutral-0);
215
+ border: var(--prizma-border-width-regular) solid var(--prizma-border-neutral-100);
216
+ border-radius: var(--prizma-border-radius-small);
217
+ text-align: start;
218
+ }
219
+
220
+ .reusability-document > * {
221
+ margin: 0;
222
+ }
223
+
224
+ .reusability-document > * + * {
225
+ margin-top: var(--prizma-spacing-12);
226
+ }
227
+
228
+ .reusability-document__meta,
229
+ .reusability-document__prose {
230
+ color: var(--prizma-text-body-800-primary);
231
+ font-family: var(--prizma-body-family);
232
+ font-size: var(--prizma-body-m-regular-font-size);
233
+ font-weight: var(--prizma-body-m-regular-font-weight);
234
+ line-height: var(--prizma-body-m-regular-line-height);
235
+ letter-spacing: var(--prizma-body-m-regular-letter-spacing);
236
+ text-align: left;
237
+ }
238
+
239
+ .reusability-document__meta {
240
+ color: var(--prizma-text-body-500-secondary);
241
+ }
@@ -0,0 +1,55 @@
1
+ import React, { type ReactNode } from 'react';
2
+ import { type PrizmaListScreenProps } from './ListScreen';
3
+ import type { PrizmaScreenActionHandler, PrizmaScreenOverrides } from './types';
4
+ import type { ReusabilityStrings } from './ReusabilityStrings';
5
+ import './ScreenLayout.css';
6
+ import './ReusabilityLayout.css';
7
+ export interface ReusabilityPrivacyPolicyScreenProps extends Omit<PrizmaListScreenProps, 'status' | 'title' | 'subtitle' | 'glyph' | 'children' | 'listAlign' | 'scrollList' | 'disclaimer' | 'ctaLabel' | 'secondaryCtaLabel' | 'linkLabel' | 'secondaryLinkLabel' | 'overlay' | 'verifiedLabel' | 'navLabel'> {
8
+ /** Module copy — this screen reads the `privacyPolicy` slice. */
9
+ strings: ReusabilityStrings;
10
+ /**
11
+ * The policy itself. HOST-supplied content, never module copy — the same
12
+ * slot contract Qualified Signature's document viewers use for the contract
13
+ * page (GUIDELINES §10): paragraphs in `.reusability-document__prose`, the
14
+ * dateline in `.reusability-document__meta`. The host supplies it in the
15
+ * session's language; it is legal text and is never machine translated.
16
+ */
17
+ body?: ReactNode;
18
+ screenId?: string;
19
+ overrides?: PrizmaScreenOverrides;
20
+ onAction?: PrizmaScreenActionHandler;
21
+ }
22
+ /**
23
+ * Reusability (Incode Bridge) — Incode's privacy policy, read inside the flow.
24
+ * Built on the List archetype (GUIDELINES.md §6-G), the way Qualified
25
+ * Signature's document viewers are: the `__list` middle is "content filling the
26
+ * space between the title block and the CTA band", which is what a document is,
27
+ * and the band carries one full-width button.
28
+ *
29
+ * Figma: `demo_5` (7877:68997), the frame the "Incode’s Privacy Policy" link
30
+ * opens — the Demo App's terms layout re-used: the Incode logo top-LEFT on a
31
+ * 32px gutter, "Last Modified: August 5, 2024", the policy as an unframed wall
32
+ * of Body/M text, and a raised white band with "Done".
33
+ *
34
+ * Three deltas from that frame, all the system's (DEVIATIONS #RU-7):
35
+ * 1. The nav is the archetype's — logo centred, no close — and the document
36
+ * sits on the column's 24px gutter like every screen in this package
37
+ * (GUIDELINES §3, §5). The frame's left logo and 32 gutter are the Demo
38
+ * App's chrome, not a module's.
39
+ * 2. The frame draws no heading. GUIDELINES §4 gives every screen exactly one
40
+ * H2 and G has no title-less path (the same delta QS's `viewdoc` records),
41
+ * so the screen carries the link's own label as its title.
42
+ * 3. The policy scrolls inside the framed reader every document viewer here
43
+ * draws (`.reusability-document`, the QS recipe), not unframed to the
44
+ * frame's edge; the title, the button and the tag hold still while it pans.
45
+ *
46
+ * The policy is the host's (`body`), like QS's contract page: the SDK owns no
47
+ * legal text and translates none — the host supplies the document in the
48
+ * session's language. "Done" is the frame's primary and emits `cta`: it
49
+ * closes the policy and returns to the selection, where nothing has changed. On the Web SDK this
50
+ * link opens the policy in a NEW TAB instead (`identityReuse.opensInNewTab`);
51
+ * this screen is the in-flow reading the frame draws, which is what a native
52
+ * host presents.
53
+ */
54
+ export declare const ReusabilityPrivacyPolicyScreen: React.ForwardRefExoticComponent<ReusabilityPrivacyPolicyScreenProps & React.RefAttributes<HTMLDivElement>>;
55
+ export default ReusabilityPrivacyPolicyScreen;
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { forwardRef } from 'react';
4
+ import { PrizmaListScreen } from './ListScreen';
5
+ import './ScreenLayout.css';
6
+ import './ReusabilityLayout.css';
7
+ /**
8
+ * Reusability (Incode Bridge) — Incode's privacy policy, read inside the flow.
9
+ * Built on the List archetype (GUIDELINES.md §6-G), the way Qualified
10
+ * Signature's document viewers are: the `__list` middle is "content filling the
11
+ * space between the title block and the CTA band", which is what a document is,
12
+ * and the band carries one full-width button.
13
+ *
14
+ * Figma: `demo_5` (7877:68997), the frame the "Incode’s Privacy Policy" link
15
+ * opens — the Demo App's terms layout re-used: the Incode logo top-LEFT on a
16
+ * 32px gutter, "Last Modified: August 5, 2024", the policy as an unframed wall
17
+ * of Body/M text, and a raised white band with "Done".
18
+ *
19
+ * Three deltas from that frame, all the system's (DEVIATIONS #RU-7):
20
+ * 1. The nav is the archetype's — logo centred, no close — and the document
21
+ * sits on the column's 24px gutter like every screen in this package
22
+ * (GUIDELINES §3, §5). The frame's left logo and 32 gutter are the Demo
23
+ * App's chrome, not a module's.
24
+ * 2. The frame draws no heading. GUIDELINES §4 gives every screen exactly one
25
+ * H2 and G has no title-less path (the same delta QS's `viewdoc` records),
26
+ * so the screen carries the link's own label as its title.
27
+ * 3. The policy scrolls inside the framed reader every document viewer here
28
+ * draws (`.reusability-document`, the QS recipe), not unframed to the
29
+ * frame's edge; the title, the button and the tag hold still while it pans.
30
+ *
31
+ * The policy is the host's (`body`), like QS's contract page: the SDK owns no
32
+ * legal text and translates none — the host supplies the document in the
33
+ * session's language. "Done" is the frame's primary and emits `cta`: it
34
+ * closes the policy and returns to the selection, where nothing has changed. On the Web SDK this
35
+ * link opens the policy in a NEW TAB instead (`identityReuse.opensInNewTab`);
36
+ * this screen is the in-flow reading the frame draws, which is what a native
37
+ * host presents.
38
+ */
39
+ export const ReusabilityPrivacyPolicyScreen = forwardRef(({ strings, body, screenId = 'reusability-privacy-policy', overrides, onAction, ...shell }, ref) => {
40
+ const { privacyPolicy } = strings;
41
+ return (_jsx(PrizmaListScreen, { ref: ref, title: privacyPolicy.title, ctaLabel: privacyPolicy.ctaLabel, verifiedLabel: strings.verifiedLabel, navLabel: strings.navLabel, screenId: screenId, overrides: overrides, onAction: onAction, ...shell, children: _jsx("div", { className: "reusability-document", role: "region", "aria-label": privacyPolicy.title, tabIndex: 0, children: body }) }));
42
+ });
43
+ ReusabilityPrivacyPolicyScreen.displayName = 'ReusabilityPrivacyPolicyScreen';
44
+ export default ReusabilityPrivacyPolicyScreen;
@@ -0,0 +1,85 @@
1
+ /** The document types the identity-reuse backend returns. The SDK's own
2
+ * vocabulary (`identityReuse.documentType.*`). */
3
+ export type ReusabilityDocumentType = 'passport' | 'idCard' | 'driversLicense';
4
+ /**
5
+ * One reusable credential, as the backend describes it — DATA, not copy. The
6
+ * host formats the date (the SDK composes "Verified" + an `Intl` short date
7
+ * client-side, `identity-reuse.tsx` `formatVerifiedAt`) and masks the number.
8
+ */
9
+ export interface ReusableCredential {
10
+ /** Stable id the host submits back on selection. */
11
+ id: string;
12
+ documentType: ReusabilityDocumentType;
13
+ /** ISO 3166-1 alpha-2. Resolves to Core's flag raster bank
14
+ * (`PrizmaCountryFlag`, 24×18); a country outside the bundled bank falls back
15
+ * to `countryFlag`. */
16
+ countryCode: string;
17
+ /** Emoji fallback for a country the raster bank does not carry — Core's own
18
+ * fallback rule for the Combined input and the Document List card. */
19
+ countryFlag?: string;
20
+ /** Already masked by the backend ("MP1******3815"). */
21
+ maskedNumber: string;
22
+ /** Already formatted by the host ("Apr 2023"). Rendered after
23
+ * `selection.verifiedPrefix`. */
24
+ verifiedOn: string;
25
+ }
26
+ export interface ReusabilityStrings {
27
+ /** "verified by" attribution in the footer tag. */
28
+ verifiedLabel: string;
29
+ /** Accessible name for the logo nav row. */
30
+ navLabel?: string;
31
+ /** The `doc selection` frames — the one screen of the module. */
32
+ selection: {
33
+ /** H2 ("Share your details for a faster verification"). */
34
+ title: string;
35
+ /** H5 under the title. The frame's recipient placeholder is `{Company B}`;
36
+ * the SDK interpolates `{{companyName}}` (`identityReuse.subtitleWithCompany`). */
37
+ subtitle: string;
38
+ /** Accessible name of the option list. */
39
+ listLabel: string;
40
+ /** The document-type label on each credential row ("Passport"). */
41
+ documentType: Record<ReusabilityDocumentType, string>;
42
+ /** The pill on the first row — the backend orders the list best match
43
+ * first, and the first is tagged ("Recommended"). */
44
+ recommendedTag: string;
45
+ /** The word before the formatted date on each row ("Verified"). The SDK
46
+ * translates only this word and appends the date locally. */
47
+ verifiedPrefix: string;
48
+ /** The last row — capture a document instead of reusing one. */
49
+ scanNewLabel: string;
50
+ /** The pill on that row ("Slowest"). */
51
+ slowestTag: string;
52
+ /** First tertiary link under the list ("What data will be shared?"):
53
+ * opens the shared-details sheet. */
54
+ sharedDataLink: string;
55
+ /** Second tertiary link ("Incode’s Privacy Policy"): opens the policy. */
56
+ privacyPolicyLink: string;
57
+ };
58
+ /** The `shared info` frame — Core's bottom sheet over the selection. */
59
+ sharedDetails: {
60
+ /** Sheet heading, Core's H1 ("Shared details"). */
61
+ title: string;
62
+ /** Under the heading ("Only the following information will be shared with
63
+ * {Company B}."). */
64
+ subtitle: string;
65
+ /** The bullet list — what the recipient asked for. In production these
66
+ * come from the recipient's data-sharing request (ENG-57939 acceptance
67
+ * criteria), so the list is host data rendered through this slot. */
68
+ items: string[];
69
+ /** The sheet's one button ("Understood"). */
70
+ ctaLabel: string;
71
+ };
72
+ /**
73
+ * The `demo_5` frame — Incode's privacy policy, read inside the flow. The
74
+ * document ITSELF is not here: it is host content (the policy at
75
+ * incode.com/privacy, in the host's language), supplied through the screen's
76
+ * `body` slot the way Qualified Signature's viewers take their contract.
77
+ */
78
+ privacyPolicy: {
79
+ /** H2 the archetype requires; the frame draws none (DEVIATIONS #RU-7).
80
+ * The link's own label ("Incode’s Privacy Policy") is the natural title. */
81
+ title: string;
82
+ /** Primary under the document ("Done"): back to the selection. */
83
+ ctaLabel: string;
84
+ };
85
+ }
@@ -0,0 +1,37 @@
1
+ // Reusability (Incode Bridge) — copy contract.
2
+ //
3
+ // The credential-reuse step of an Incode Bridge session: a returning person
4
+ // who already verified with another member of the network is offered the
5
+ // document they verified there, so they can skip ID capture at the company
6
+ // they are onboarding with now. The SDK module is `identity-reuse`
7
+ // (`incode-identity-reuse`, i18n namespace `identityReuse`); the product name
8
+ // is Incode Bridge; the design file calls it Reusability. Bridge is NOT Trust
9
+ // Graph: it moves the person's own credential, with their consent, to remove
10
+ // friction — it makes no fraud claim (MVP spec, Notion, 2026-08-17).
11
+ //
12
+ // Figma: `Reusability - In Experimentation` (f4AsCbOBP29IbTQLxBNgNG), section
13
+ // `Reusability Iterations` (7877:68814) — the iteration Camila shared with the
14
+ // Identity team on 2026-09-19 and that the Web SDK built as ENG-57939 (Dusan,
15
+ // PR #1021, "one-click credential selection with shared-data sheet"). Four
16
+ // frames:
17
+ // · 7877:68816 `doc selection` Multiple documents — two reusable passports
18
+ // and the "Scan a new document" row
19
+ // · 7877:68875 `doc selection` Single document — one passport and the row
20
+ // · 7877:68927 `shared info` Shared data — Core's bottom sheet over the
21
+ // selection listing what will be shared
22
+ // · 7877:68997 `demo_5` Privacy Policy — Incode's policy, read in
23
+ // the flow, Done at the bottom
24
+ //
25
+ // Two product decisions shape the copy (consent review with legal, Granola
26
+ // 2026-09-16; Vlado, #reusability 2026-09-15):
27
+ // 1. The subtitle says WHO holds the data and that Incode only passes it:
28
+ // "A company you previously verified with holds a document you can reuse.
29
+ // Incode only passes it to {Company B}." The donor is never named (it may
30
+ // be a regulated entity); the recipient is.
31
+ // 2. Selecting a document ADVANCES — no confirm button. A mis-tap is
32
+ // recovered with the nav's way back, not with a second step.
33
+ //
34
+ // No hardcoded English anywhere in a screen: every visible string arrives
35
+ // here, so the host's locale pack drives the module. The SDK's `identityReuse`
36
+ // namespace already carries ES and PT for almost every sentence below.
37
+ export {};
@@ -3,18 +3,24 @@ import { type PrizmaScreenShellProps } from './ScreenShell';
3
3
  import type { PrizmaScreenActionHandler, PrizmaScreenChromeProps, PrizmaScreenOverrides } from './types';
4
4
  import './ScreenLayout.css';
5
5
  /**
6
- * The three stages every captured-media review section shares. Identical
7
- * skeleton — only the header block (Title vs loading bar), the media's own
8
- * state and the presence of the CTA row change. Named to match the modules'
9
- * own stage axis (`DocumentCaptureConfirmStage`, Video Selfie's review step).
6
+ * The stages a captured-media review section shares. Identical skeleton —
7
+ * only the header block (Title vs loading bar), the media's own state and
8
+ * the presence of the CTA row change. `review`/`analyzing`/`success` name the
9
+ * modules' own confirm-flow axis (`DocumentCaptureConfirmStage`, Video
10
+ * Selfie's review step); `error` is Digital ID Upload-only so far — its
11
+ * verdict screen shows the SAME rejected-file media the confirm flow does
12
+ * (`PrizmaCaptureDigitalId state="error"`), drawn with the identical
13
+ * header/media/CTA skeleton as `analyzing`/`success` (`Upload Digital ID`
14
+ * file wxFsHRvllern4VnjRqM4JO, node 25874:11957) — not archetype F, whose
15
+ * verdict screens carry no media stage of their own.
10
16
  */
11
- export type PrizmaReviewStage = 'review' | 'analyzing' | 'success';
17
+ export type PrizmaReviewStage = 'review' | 'analyzing' | 'success' | 'error';
12
18
  export interface PrizmaReviewScreenProps extends Omit<PrizmaScreenShellProps, 'dark' | 'title' | 'children'>, Pick<PrizmaScreenChromeProps, 'showHeader' | 'showFooter'> {
13
19
  /** Which review stage to render. Default `review`. */
14
20
  stage?: PrizmaReviewStage;
15
21
  /** H2 review/base title ("Review your document"). */
16
22
  title: string;
17
- /** Supporting copy under the title — drawn on `review` only (Figma). */
23
+ /** Supporting copy under the title — drawn on `review`/`error` (Figma). */
18
24
  subtitle?: string;
19
25
  /** Title shown on `success`; falls back to `title` when omitted. */
20
26
  successTitle?: string;
@@ -28,6 +34,25 @@ export interface PrizmaReviewScreenProps extends Omit<PrizmaScreenShellProps, 'd
28
34
  analyzingState?: 'analyzing' | 'uploading';
29
35
  /** Loading-bar progress on `analyzing`, 0–100. */
30
36
  progress?: number;
37
+ /**
38
+ * Only takes effect while the nav is hidden (`showHeader=false` — every
39
+ * current no-nav stage is `analyzing`/`success`). Default `false` —
40
+ * Document Capture's verified layout (DEVIATIONS #DC-22/24): the header
41
+ * sits where a title normally would, Spacing/32 above the stage, and
42
+ * whatever follows (the stage, then an optional band) centres or flows
43
+ * independently.
44
+ *
45
+ * `true`: the header and the media centre as ONE group — leftover space
46
+ * splits evenly above the header and below the trailing content (the CTA
47
+ * band, or nothing) — because with no nav the header has nothing to anchor
48
+ * to. Digital ID Upload's Figma draws BOTH its no-nav stages this way: a
49
+ * top flex-1 region bottom-anchoring the header, the fixed media, then a
50
+ * bottom flex-1 region (empty on `analyzing`, bottom-anchoring the CTA on
51
+ * `success`) — `Upload Digital ID` file wxFsHRvllern4VnjRqM4JO, nodes
52
+ * 25351:14726 (analyzing) / 25351:14727 (success). `review` always shows
53
+ * its own nav, so this is a no-op there regardless of the value passed.
54
+ */
55
+ centeredWhenNoNav?: boolean;
31
56
  /**
32
57
  * The flexing captured-media slot: a `PrizmaIdCapture` still, an uploaded-file
33
58
  * preview card, a portrait review. Kept a slot so one template serves every
@@ -42,7 +67,7 @@ export interface PrizmaReviewScreenProps extends Omit<PrizmaScreenShellProps, 'd
42
67
  * offset and footer all come from ScreenLayout.css regardless.
43
68
  */
44
69
  stageClassName?: string;
45
- /** Primary CTA — the forward action. Drawn on `review` and `success`. */
70
+ /** Primary CTA — the forward action. Drawn on `review`, `success`, `error`. */
46
71
  primaryLabel: string;
47
72
  /** Secondary CTA ("Replace" / "Retake") — drawn on `review` only. */
48
73
  secondaryLabel?: string;
@@ -57,11 +82,12 @@ export interface PrizmaReviewScreenProps extends Omit<PrizmaScreenShellProps, 'd
57
82
  * Archetype H — Review (captured-media confirmation).
58
83
  *
59
84
  * The "header → flexing captured-media stage → CTA band → tag" recipe, with a
60
- * `review → analyzing → success` stage axis. It exists because two Document
61
- * Capture screens hand-built it independently (`DocumentCaptureConfirmImage`,
62
- * `DocumentCaptureConfirmUpload`) with their own three-band arithmetic in
63
- * `DocumentCaptureLayout.css`, and Video Selfie's review step needs the same
64
- * skeleton — a captured still under a title, confirmed or replaced.
85
+ * `review → analyzing → success` stage axis (+ `error`, see `PrizmaReviewStage`).
86
+ * It exists because two Document Capture screens hand-built it independently
87
+ * (`DocumentCaptureConfirmImage`, `DocumentCaptureConfirmUpload`) with their
88
+ * own three-band arithmetic in `DocumentCaptureLayout.css`, and Video Selfie's
89
+ * review step needs the same skeleton — a captured still under a title,
90
+ * confirmed or replaced.
65
91
  *
66
92
  * It is NOT archetype F (Result): F centres a small status + CTA block, while a
67
93
  * review TOP-aligns the header over a large media stage that flexes to fill the
@@ -12,11 +12,12 @@ import './ScreenLayout.css';
12
12
  * Archetype H — Review (captured-media confirmation).
13
13
  *
14
14
  * The "header → flexing captured-media stage → CTA band → tag" recipe, with a
15
- * `review → analyzing → success` stage axis. It exists because two Document
16
- * Capture screens hand-built it independently (`DocumentCaptureConfirmImage`,
17
- * `DocumentCaptureConfirmUpload`) with their own three-band arithmetic in
18
- * `DocumentCaptureLayout.css`, and Video Selfie's review step needs the same
19
- * skeleton — a captured still under a title, confirmed or replaced.
15
+ * `review → analyzing → success` stage axis (+ `error`, see `PrizmaReviewStage`).
16
+ * It exists because two Document Capture screens hand-built it independently
17
+ * (`DocumentCaptureConfirmImage`, `DocumentCaptureConfirmUpload`) with their
18
+ * own three-band arithmetic in `DocumentCaptureLayout.css`, and Video Selfie's
19
+ * review step needs the same skeleton — a captured still under a title,
20
+ * confirmed or replaced.
20
21
  *
21
22
  * It is NOT archetype F (Result): F centres a small status + CTA block, while a
22
23
  * review TOP-aligns the header over a large media stage that flexes to fill the
@@ -32,25 +33,57 @@ import './ScreenLayout.css';
32
33
  * to the bottom itself. Every offset lives in ScreenLayout.css; this file
33
34
  * declares none of its own.
34
35
  */
35
- export const PrizmaReviewScreen = forwardRef(({ stage = 'review', title, subtitle, successTitle, analyzingLabel, analyzingState = 'analyzing', progress = 0, children, stageClassName, primaryLabel, secondaryLabel, verifiedLabel, navLabel, showHeader, showFooter = true, screenId, overrides, onAction, ...shell }, ref) => {
36
+ export const PrizmaReviewScreen = forwardRef(({ stage = 'review', title, subtitle, successTitle, analyzingLabel, analyzingState = 'analyzing', progress = 0, centeredWhenNoNav = false, children, stageClassName, primaryLabel, secondaryLabel, verifiedLabel, navLabel, showHeader, showFooter = true, screenId, overrides, onAction, ...shell }, ref) => {
36
37
  // Review screens are the capture family: no logo unless the client opts in
37
38
  // by supplying one (types.ts chrome contract). `showHeader` still wins when
38
39
  // set explicitly.
39
40
  const withNav = showHeader ?? Boolean(overrides?.logo);
40
41
  const showSecondary = stage === 'review' && Boolean(secondaryLabel);
41
42
  const showBand = stage !== 'analyzing' && Boolean(primaryLabel || secondaryLabel);
43
+ const centeredGroup = !withNav && centeredWhenNoNav;
42
44
  return (_jsxs(PrizmaScreenShell, { ref: ref, ...shell, children: [withNav ? (_jsx(PrizmaScreenNav, { logo: overrides?.logo, navLabel: navLabel })) : null, _jsxs("div", { className: [
43
45
  'prizma-screen-layout__content',
44
46
  withNav ? '' : 'prizma-screen-layout__content--no-nav',
45
47
  ]
46
48
  .filter(Boolean)
47
- .join(' '), children: [_jsx("div", { className: "prizma-screen-layout__review-header", children: stage === 'analyzing' ? (_jsx("div", { className: "prizma-screen-layout__review-loading", children: _jsx(PrizmaLoadingBar, { state: analyzingState, progress: progress, title: analyzingLabel }) })) : (_jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: stage === 'success' ? successTitle ?? title : title, showSubtitle: stage === 'review' && Boolean(subtitle), subtitle: subtitle, icon: stage === 'success' ? { type: 'status', status: 'success' } : undefined })) }), _jsx("div", { className: [
49
+ .join(' '), children: [_jsx("div", { className: [
50
+ 'prizma-screen-layout__review-header',
51
+ centeredGroup ? 'prizma-screen-layout__review-header--centered' : '',
52
+ ]
53
+ .filter(Boolean)
54
+ .join(' '), children: stage === 'analyzing' ? (_jsx("div", { className: "prizma-screen-layout__review-loading", children: _jsx(PrizmaLoadingBar, { state: analyzingState, progress: progress, title: analyzingLabel }) })) : (_jsx(PrizmaTitle, { variant: overrides?.align === 'left' ? 'left' : 'centered', title: stage === 'success' ? successTitle ?? title : title, showSubtitle: (stage === 'review' || stage === 'error') && Boolean(subtitle), subtitle: subtitle, icon: stage === 'success'
55
+ ? { type: 'status', status: 'success' }
56
+ : stage === 'error'
57
+ ? { type: 'status', status: 'error' }
58
+ : undefined })) }), _jsx("div", { className: [
48
59
  'prizma-screen-layout__review-stage',
49
60
  stage === 'analyzing' ? 'prizma-screen-layout__review-stage--flush' : '',
61
+ centeredGroup ? 'prizma-screen-layout__review-stage--centered-group' : '',
50
62
  stageClassName ?? '',
51
63
  ]
52
64
  .filter(Boolean)
53
- .join(' '), children: children }), showBand ? (_jsx("div", { className: "prizma-screen-layout__band prizma-screen-layout__band--review", children: _jsx(PrizmaButtonGroup, { orientation: "horizontal-v1", showSecondary: showSecondary, primaryLabel: primaryLabel, onPrimaryClick: () => onAction?.({ type: 'cta', screenId }), secondaryLabel: secondaryLabel, onSecondaryClick: () => onAction?.({ type: 'secondary', screenId }) }) })) : null, showFooter ? (_jsx("div", { className: "prizma-screen-layout__band__tag", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })] }));
65
+ .join(' '), children: children }), (() => {
66
+ const band = showBand ? (_jsx("div", { className: [
67
+ 'prizma-screen-layout__band',
68
+ 'prizma-screen-layout__band--review',
69
+ // No footer tag to reserve the bottom space (§6, owner rule
70
+ // 2026-08-18: header/footer are independently controlled) —
71
+ // fall back to the band's own Spacing/24, same as any other
72
+ // screen that "genuinely carries no tag" (ScreenLayout.css).
73
+ // Otherwise the CTA sits flush against the shell edge.
74
+ !showFooter ? 'prizma-screen-layout__band--bare' : '',
75
+ ]
76
+ .filter(Boolean)
77
+ .join(' '), children: _jsx(PrizmaButtonGroup, { orientation: "horizontal-v1", showSecondary: showSecondary, primaryLabel: primaryLabel, onPrimaryClick: () => onAction?.({ type: 'cta', screenId }), secondaryLabel: secondaryLabel, onSecondaryClick: () => onAction?.({ type: 'secondary', screenId }) }) })) : null;
78
+ // Balances the header's own flex-1 (`--centered`) so the header +
79
+ // media sit as one group centred between equal top/bottom space,
80
+ // instead of the media alone centring below a pinned header. The
81
+ // band (if any — `success`) bottom-anchors inside this same
82
+ // trailing region instead of just following the stage, matching
83
+ // Figma's own bottom flex-1 container; `analyzing` carries no
84
+ // band, so the region is just an empty spacer.
85
+ return centeredGroup ? (_jsx("div", { className: "prizma-screen-layout__review-trailing", children: band })) : (band);
86
+ })(), showFooter ? (_jsx("div", { className: "prizma-screen-layout__band__tag", children: _jsx(PrizmaTag, { label: verifiedLabel }) })) : null] })] }));
54
87
  });
55
88
  PrizmaReviewScreen.displayName = 'PrizmaReviewScreen';
56
89
  export default PrizmaReviewScreen;