@incodetech/prizma-core-screens 0.2.7 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BiometricConsentScreen.d.ts +95 -0
- package/dist/BiometricConsentScreen.js +91 -0
- package/dist/BiometricConsentStrings.d.ts +84 -0
- package/dist/BiometricConsentStrings.js +31 -0
- package/dist/CaptureScreen.d.ts +13 -0
- package/dist/CaptureScreen.js +2 -2
- package/dist/DemoScreensLayout.css +16 -0
- package/dist/DemoScreensRedirectScreen.d.ts +6 -1
- package/dist/DemoScreensRedirectScreen.js +3 -2
- package/dist/DemoScreensStrings.d.ts +5 -0
- package/dist/DigitalIdDeviceWalletsDocumentSelectionScreen.d.ts +34 -0
- package/dist/DigitalIdDeviceWalletsDocumentSelectionScreen.js +47 -0
- package/dist/DigitalIdDeviceWalletsResultScreen.d.ts +28 -0
- package/dist/DigitalIdDeviceWalletsResultScreen.js +23 -0
- package/dist/DigitalIdDeviceWalletsStrings.d.ts +55 -0
- package/dist/DigitalIdDeviceWalletsStrings.js +19 -0
- package/dist/DigitalIdProvidersDocumentSelectionScreen.d.ts +31 -0
- package/dist/DigitalIdProvidersDocumentSelectionScreen.js +37 -0
- package/dist/DigitalIdProvidersErrorScreen.d.ts +33 -0
- package/dist/DigitalIdProvidersErrorScreen.js +33 -0
- package/dist/DigitalIdProvidersLayout.css +59 -0
- package/dist/DigitalIdProvidersRedirectScreen.d.ts +24 -0
- package/dist/DigitalIdProvidersRedirectScreen.js +18 -0
- package/dist/DigitalIdProvidersStrings.d.ts +72 -0
- package/dist/DigitalIdProvidersStrings.js +15 -0
- package/dist/DigitalIdUploadErrorScreen.d.ts +31 -0
- package/dist/DigitalIdUploadErrorScreen.js +26 -0
- package/dist/DigitalIdUploadFileTooLargeScreen.d.ts +27 -0
- package/dist/DigitalIdUploadFileTooLargeScreen.js +21 -0
- package/dist/DigitalIdUploadReviewScreen.d.ts +57 -0
- package/dist/DigitalIdUploadReviewScreen.js +44 -0
- package/dist/DigitalIdUploadStrings.d.ts +64 -0
- package/dist/DigitalIdUploadStrings.js +19 -0
- package/dist/DigitalIdUploadTutorialScreen.d.ts +28 -0
- package/dist/DigitalIdUploadTutorialScreen.js +23 -0
- package/dist/DocumentCaptureIllustration.d.ts +1 -1
- package/dist/EkybCountryScreen.d.ts +6 -6
- package/dist/EkybCountryScreen.js +20 -7
- package/dist/EkybStrings.d.ts +6 -1
- package/dist/ErrorScreensScreen.d.ts +5 -2
- package/dist/ErrorScreensScreen.js +15 -4
- package/dist/ErrorScreensStrings.d.ts +17 -2
- package/dist/ErrorScreensStrings.js +18 -10
- package/dist/FaceCaptureCapturingScreen.d.ts +63 -0
- package/dist/FaceCaptureCapturingScreen.js +62 -2
- package/dist/FaceCaptureLayout.css +69 -4
- package/dist/FaceCaptureStrings.d.ts +23 -0
- package/dist/FormScreen.css +14 -0
- package/dist/FormScreen.d.ts +28 -0
- package/dist/FormScreen.js +3 -2
- package/dist/IdCaptureLayout.css +165 -2
- package/dist/IdCaptureStageScreen.d.ts +47 -0
- package/dist/IdCaptureStageScreen.js +39 -3
- package/dist/IdCaptureStrings.d.ts +19 -0
- package/dist/ListScreen.d.ts +19 -0
- package/dist/ListScreen.js +7 -2
- package/dist/LoaderScreen.d.ts +7 -5
- package/dist/LoaderScreen.js +7 -5
- package/dist/LoadersStrings.d.ts +18 -5
- package/dist/OcrReviewErrorScreen.d.ts +30 -0
- package/dist/OcrReviewErrorScreen.js +24 -0
- package/dist/OcrReviewLayout.css +24 -0
- package/dist/OcrReviewLoadingScreen.d.ts +25 -0
- package/dist/OcrReviewLoadingScreen.js +19 -0
- package/dist/OcrReviewScreen.d.ts +76 -0
- package/dist/OcrReviewScreen.js +65 -0
- package/dist/OcrReviewStrings.d.ts +47 -0
- package/dist/OcrReviewStrings.js +17 -0
- package/dist/OcrReviewSuccessScreen.d.ts +30 -0
- package/dist/OcrReviewSuccessScreen.js +24 -0
- package/dist/PermissionsAllowScreen.d.ts +8 -11
- package/dist/PermissionsAllowScreen.js +8 -11
- package/dist/PermissionsAskScreen.d.ts +41 -0
- package/dist/PermissionsAskScreen.js +43 -0
- package/dist/PermissionsBrowserStepsScreen.d.ts +9 -2
- package/dist/PermissionsBrowserStepsScreen.js +12 -3
- package/dist/PermissionsLayout.css +47 -0
- package/dist/PermissionsStrings.d.ts +20 -9
- package/dist/PermissionsStrings.js +10 -4
- package/dist/PhoneInputOtpScreen.d.ts +8 -0
- package/dist/PhoneInputOtpScreen.js +26 -19
- package/dist/PhoneInputStrings.d.ts +11 -3
- package/dist/PhoneInputVerifyScreen.js +21 -5
- package/dist/QualifiedSignatureDocumentScreen.d.ts +8 -5
- package/dist/QualifiedSignatureDocumentScreen.js +9 -6
- package/dist/QualifiedSignatureResultScreen.d.ts +16 -13
- package/dist/QualifiedSignatureResultScreen.js +17 -18
- package/dist/QualifiedSignatureStrings.d.ts +11 -4
- package/dist/ResultScreen.d.ts +8 -0
- package/dist/ResultScreen.js +14 -3
- package/dist/ReusabilityCredentialSelectionScreen.d.ts +95 -0
- package/dist/ReusabilityCredentialSelectionScreen.js +94 -0
- package/dist/ReusabilityLayout.css +241 -0
- package/dist/ReusabilityPrivacyPolicyScreen.d.ts +55 -0
- package/dist/ReusabilityPrivacyPolicyScreen.js +44 -0
- package/dist/ReusabilityStrings.d.ts +85 -0
- package/dist/ReusabilityStrings.js +37 -0
- package/dist/ReviewScreen.d.ts +38 -12
- package/dist/ReviewScreen.js +41 -8
- package/dist/ScreenLayout.css +382 -6
- package/dist/VideoSelfieErrorScreen.js +1 -1
- package/dist/VideoSelfieIdCaptureScreen.js +1 -1
- package/dist/VideoSelfieLayout.css +304 -2
- package/dist/VideoSelfieSelfieCaptureScreen.js +1 -1
- package/dist/VideoSelfieSpeakScreen.js +1 -1
- package/dist/VideoSelfieStrings.d.ts +4 -1
- package/dist/VideoSelfieTurnHeadScreen.js +14 -11
- package/dist/VideoSelfieTutorialScreen.d.ts +9 -0
- package/dist/VideoSelfieTutorialScreen.js +10 -1
- package/dist/VideoSelfieWaveScreen.js +1 -1
- package/dist/ViewfinderScreen.css +36 -0
- package/dist/flows.d.ts +8 -0
- package/dist/flows.js +17 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +17 -0
- package/dist/styles.css +4 -0
- package/package.json +94 -3
- package/samples/video-selfie-camera-wide.jpg +0 -0
- package/samples/video-selfie-room-wide.jpg +0 -0
- package/src/BiometricConsentScreen.tsx +192 -0
- package/src/BiometricConsentStrings.ts +119 -0
- package/src/CaptureScreen.tsx +17 -0
- package/src/DemoScreensLayout.css +16 -0
- package/src/DemoScreensRedirectScreen.tsx +14 -6
- package/src/DemoScreensStrings.ts +5 -0
- package/src/DigitalIdDeviceWalletsDocumentSelectionScreen.tsx +108 -0
- package/src/DigitalIdDeviceWalletsResultScreen.tsx +76 -0
- package/src/DigitalIdDeviceWalletsStrings.ts +80 -0
- package/src/DigitalIdProvidersDocumentSelectionScreen.tsx +112 -0
- package/src/DigitalIdProvidersErrorScreen.tsx +104 -0
- package/src/DigitalIdProvidersLayout.css +59 -0
- package/src/DigitalIdProvidersRedirectScreen.tsx +65 -0
- package/src/DigitalIdProvidersStrings.ts +98 -0
- package/src/DigitalIdUploadErrorScreen.tsx +83 -0
- package/src/DigitalIdUploadFileTooLargeScreen.tsx +67 -0
- package/src/DigitalIdUploadReviewScreen.tsx +119 -0
- package/src/DigitalIdUploadStrings.ts +88 -0
- package/src/DigitalIdUploadTutorialScreen.tsx +59 -0
- package/src/DocumentCaptureIllustration.tsx +1 -1
- package/src/EkybCountryScreen.tsx +23 -6
- package/src/EkybStrings.ts +6 -1
- package/src/ErrorScreensScreen.tsx +15 -4
- package/src/ErrorScreensStrings.ts +37 -12
- package/src/FaceCaptureCapturingScreen.tsx +102 -13
- package/src/FaceCaptureLayout.css +69 -4
- package/src/FaceCaptureStrings.ts +24 -0
- package/src/FormScreen.css +14 -0
- package/src/FormScreen.tsx +34 -0
- package/src/IdCaptureLayout.css +165 -2
- package/src/IdCaptureStageScreen.tsx +75 -0
- package/src/IdCaptureStrings.ts +19 -0
- package/src/ListScreen.tsx +48 -9
- package/src/LoaderScreen.tsx +7 -5
- package/src/LoadersStrings.ts +18 -5
- package/src/OcrReviewErrorScreen.tsx +53 -0
- package/src/OcrReviewLayout.css +24 -0
- package/src/OcrReviewLoadingScreen.tsx +48 -0
- package/src/OcrReviewScreen.tsx +190 -0
- package/src/OcrReviewStrings.ts +69 -0
- package/src/OcrReviewSuccessScreen.tsx +52 -0
- package/src/PermissionsAllowScreen.tsx +9 -10
- package/src/PermissionsAskScreen.tsx +105 -0
- package/src/PermissionsBrowserStepsScreen.tsx +11 -3
- package/src/PermissionsLayout.css +47 -0
- package/src/PermissionsStrings.ts +42 -12
- package/src/PhoneInputOtpScreen.tsx +23 -3
- package/src/PhoneInputStrings.ts +11 -3
- package/src/PhoneInputVerifyScreen.tsx +24 -4
- package/src/QualifiedSignatureDocumentScreen.tsx +9 -7
- package/src/QualifiedSignatureResultScreen.tsx +28 -26
- package/src/QualifiedSignatureStrings.ts +11 -4
- package/src/ResultScreen.tsx +33 -2
- package/src/ReusabilityCredentialSelectionScreen.tsx +246 -0
- package/src/ReusabilityLayout.css +241 -0
- package/src/ReusabilityPrivacyPolicyScreen.tsx +109 -0
- package/src/ReusabilityStrings.ts +127 -0
- package/src/ReviewScreen.tsx +96 -27
- package/src/ScreenLayout.css +382 -6
- package/src/VideoSelfieErrorScreen.tsx +1 -1
- package/src/VideoSelfieIdCaptureScreen.tsx +9 -1
- package/src/VideoSelfieLayout.css +304 -2
- package/src/VideoSelfieSelfieCaptureScreen.tsx +9 -1
- package/src/VideoSelfieSpeakScreen.tsx +9 -1
- package/src/VideoSelfieStrings.ts +4 -2
- package/src/VideoSelfieTurnHeadScreen.tsx +25 -14
- package/src/VideoSelfieTutorialScreen.tsx +11 -0
- package/src/VideoSelfieWaveScreen.tsx +9 -1
- package/src/ViewfinderScreen.css +36 -0
- package/src/flows.ts +25 -0
- package/src/index.ts +116 -3
- package/src/styles.css +4 -0
|
@@ -6,19 +6,27 @@
|
|
|
6
6
|
// 214:3357 Geolocation.error.noNetwork → `noConnection`
|
|
7
7
|
// 240:154 Error screen - Unsupported browser → `unsupportedBrowser`
|
|
8
8
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
9
|
+
// plus the one failure every module draws for itself and the file never did:
|
|
10
|
+
//
|
|
11
|
+
// — <module>.error "Something went wrong" → `somethingWentWrong`
|
|
12
|
+
//
|
|
13
|
+
// The failures that belong to the SESSION rather than to any module: the link
|
|
14
|
+
// has expired, the network went away, the browser cannot run the SDK, the
|
|
15
|
+
// server said no for a reason the user cannot act on. Every module can hit all
|
|
16
|
+
// four, which is why they are recorded once in the generic family — a user who
|
|
17
|
+
// sees three different "no internet" screens in one journey reads them as three
|
|
18
|
+
// different products.
|
|
14
19
|
//
|
|
15
20
|
// `noConnection` is deliberately the same screen every module already ships
|
|
16
21
|
// (`FaceCaptureNoConnectionScreen`, `IdCaptureNoConnectionScreen`,
|
|
17
|
-
// `DocumentCaptureNoConnectionScreen`, `GeolocationErrorScreen`'s `noNetwork
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
+
// `DocumentCaptureNoConnectionScreen`, `GeolocationErrorScreen`'s `noNetwork`,
|
|
23
|
+
// Phone Input's and Video Selfie's `noConnection`). `somethingWentWrong` is the
|
|
24
|
+
// same screen eKYC, eKYB, Forms, Email Input, Phone Input, Certificate
|
|
25
|
+
// Issuance, both signatures and Video Selfie already ship. The generic entry is
|
|
26
|
+
// where the shape and the copy are DOCUMENTED; the module copies stay put until
|
|
27
|
+
// someone retires them deliberately, because deleting exported components to
|
|
28
|
+
// save one screen is a breaking change for every host that imports them.
|
|
29
|
+
// Flagged for the owner (DEVIATIONS #GEN-7, #GEN-18).
|
|
22
30
|
//
|
|
23
31
|
// The family has no flow of its own: each of these is entered from wherever the
|
|
24
32
|
// session broke and exits to a retry or to nothing. Core Lab lists it as a
|
|
@@ -27,15 +35,17 @@
|
|
|
27
35
|
// No hardcoded English anywhere in a screen: every visible string arrives here.
|
|
28
36
|
|
|
29
37
|
/**
|
|
30
|
-
* The
|
|
38
|
+
* The four sections.
|
|
31
39
|
* - `sessionExpired` — the link is dead; the user must go back to the provider
|
|
32
40
|
* - `noConnection` — the network went away; retry when it returns
|
|
33
41
|
* - `unsupportedBrowser` — the SDK cannot run here; copy the link and move
|
|
42
|
+
* - `somethingWentWrong` — the generic failure; try again, or nothing, or quit
|
|
34
43
|
*/
|
|
35
44
|
export type ErrorScreensVariant =
|
|
36
45
|
| 'sessionExpired'
|
|
37
46
|
| 'noConnection'
|
|
38
|
-
| 'unsupportedBrowser'
|
|
47
|
+
| 'unsupportedBrowser'
|
|
48
|
+
| 'somethingWentWrong';
|
|
39
49
|
|
|
40
50
|
export interface ErrorScreensCopy {
|
|
41
51
|
title: string;
|
|
@@ -63,4 +73,19 @@ export interface ErrorScreensStrings {
|
|
|
63
73
|
/** Snackbar copy after the link is copied — the frame's second state. */
|
|
64
74
|
copiedLabel: string;
|
|
65
75
|
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The generic failure. Three ways the modules fill it, all the same screen:
|
|
79
|
+
* `ctaLabel` "Try again" (eKYC, eKYB, Forms, Email Input);
|
|
80
|
+
* no `ctaLabel`, a dead end (Certificate Issuance, Qualified Signature);
|
|
81
|
+
* `ctaLabel` plus `quitLabel`, the way out under the retry (Video Selfie).
|
|
82
|
+
* Phone Input's `unknown` fills it with "Continue" instead, because a retry
|
|
83
|
+
* may not be possible there (owner, 2026-10-09) — the CTA is the module's
|
|
84
|
+
* call; the shape and the title are what the family fixes.
|
|
85
|
+
* The title never carries an ellipsis — a failure is not in progress.
|
|
86
|
+
*/
|
|
87
|
+
somethingWentWrong: ErrorScreensCopy & {
|
|
88
|
+
/** Tertiary link under the CTA — "Quit process". Omit for no way out. */
|
|
89
|
+
quitLabel?: string;
|
|
90
|
+
};
|
|
66
91
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { forwardRef, type ReactNode } from 'react';
|
|
2
2
|
import type { PrizmaSelfieCaptureState } from '@incodetech/prizma-core-web/selfie-capture';
|
|
3
|
+
import { PrizmaSnackbar } from '@incodetech/prizma-core-web/snackbar';
|
|
3
4
|
import { PrizmaCaptureScreen, type PrizmaCaptureScreenProps } from './CaptureScreen';
|
|
4
5
|
import type {
|
|
5
6
|
FaceCaptureCapturingState,
|
|
@@ -46,6 +47,19 @@ export interface FaceCaptureCapturingScreenProps
|
|
|
46
47
|
state?: FaceCaptureCapturingState;
|
|
47
48
|
/** Live camera feed (<video>) or sample still (<img>) for the ring window. */
|
|
48
49
|
camera?: ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Raise the "Need more time?" offer over the feed — the accessibility
|
|
52
|
+
* notification shown 20 s before auto capture falls back to manual.
|
|
53
|
+
*
|
|
54
|
+
* It is a MODIFIER of whatever capturing state is already on screen, not a
|
|
55
|
+
* sixteenth state: the timer runs underneath the guidance, so the user can be
|
|
56
|
+
* told to move closer and offered more time in the same frame. Needs
|
|
57
|
+
* `strings.extendTime`; without it the flag is a no-op, which is what a host
|
|
58
|
+
* that has not localized the copy should get rather than English.
|
|
59
|
+
*/
|
|
60
|
+
extendTime?: boolean;
|
|
61
|
+
/** Tapping "Extend auto-capture". The host resets its own fallback timer. */
|
|
62
|
+
onExtendTime?: () => void;
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
/**
|
|
@@ -65,6 +79,56 @@ export interface FaceCaptureCapturingScreenProps
|
|
|
65
79
|
*
|
|
66
80
|
* The archetype adds no offsets of its own — the component owns that spacing
|
|
67
81
|
* (same deviation row).
|
|
82
|
+
*
|
|
83
|
+
* ── The "Need more time?" offer (`extendTime`) ──────────────────────────────
|
|
84
|
+
*
|
|
85
|
+
* Auto capture gives up after a configured timeout and drops the user into
|
|
86
|
+
* manual capture. Someone who is struggling — a tremor, low vision, bad light,
|
|
87
|
+
* an unfamiliar phone — gets moved off the EASIER path precisely because they
|
|
88
|
+
* were slow, which is backwards. So 20 s before the switch, the screen offers
|
|
89
|
+
* to stay on auto. A client turns it on per flow from the dashboard; with it
|
|
90
|
+
* off, nothing about today's capture changes.
|
|
91
|
+
*
|
|
92
|
+
* NOT a nicety — it is the conformance route for WCAG 2.2.1 Timing Adjustable
|
|
93
|
+
* via the *Extend* clause (warn before the limit, ≥20 s to act, ≥10 extensions).
|
|
94
|
+
* Two things follow that the visuals cannot settle: the notice must be able to
|
|
95
|
+
* come back ten times, and it must be ANNOUNCED early enough to be acted on.
|
|
96
|
+
*
|
|
97
|
+
* ── Live-region politeness: `role="alert"`, not the default ────────────────
|
|
98
|
+
*
|
|
99
|
+
* SETTLED 2026-10-05 (Camila). The Snackbar computes `role="status"` (polite)
|
|
100
|
+
* for every state but error, and this instance overrides it to `alert`.
|
|
101
|
+
*
|
|
102
|
+
* A polite region is allowed to wait until the screen reader finishes whatever
|
|
103
|
+
* it is already saying — and on this screen it always IS saying something: the
|
|
104
|
+
* capture instruction under the ring changes as the face moves, so the queue
|
|
105
|
+
* is rarely empty. The offer has a 20 s life. Queued behind two or three
|
|
106
|
+
* guidance announcements it can be read out after it has already expired,
|
|
107
|
+
* which turns the one affordance a struggling user needs into an
|
|
108
|
+
* announcement that the limit has passed.
|
|
109
|
+
*
|
|
110
|
+
* That is not a polish issue, it is the conformance failing: WCAG 2.2.1's
|
|
111
|
+
* Extend clause requires the warning to be given in time to ACT on it. An
|
|
112
|
+
* announcement the user cannot act on does not satisfy it, however correct the
|
|
113
|
+
* visuals. `alert` is assertive, so it interrupts the guidance and is heard
|
|
114
|
+
* while the 20 s is still running.
|
|
115
|
+
*
|
|
116
|
+
* The usual objection to `alert` is that interrupting is rude. It applies to
|
|
117
|
+
* notices that can wait; this one cannot, and it is strictly better to
|
|
118
|
+
* interrupt "Move closer" than to let the window close in silence. It is also
|
|
119
|
+
* why the offer must not be re-raised on a timer — each new `alert` interrupts
|
|
120
|
+
* again. It appears once per countdown, and WCAG allows that up to ten times.
|
|
121
|
+
*
|
|
122
|
+
* ⚠ NEW, not yet authored in Core. Two parts of this notice have no Figma
|
|
123
|
+
* variant behind them and are drawn from the exploration, not from the SoT:
|
|
124
|
+
* • the bold title line — the Snackbar has no `title` slot, so it rides
|
|
125
|
+
* inside `children` as a <strong>. Core to decide whether to adopt a real
|
|
126
|
+
* slot, at which point this moves onto it.
|
|
127
|
+
* • the state — it is `neutral` (blue surface, ⓘ glyph), Camila's call
|
|
128
|
+
* 2026-10-05. `warning` would signal attention more sharply but turns the
|
|
129
|
+
* surface amber, and the exploration's open question is whether amber
|
|
130
|
+
* reads as "hurry up" to someone who was already struggling. The icon
|
|
131
|
+
* cannot be chosen independently: `ICON_BY_STATE` binds it to `state`.
|
|
68
132
|
*/
|
|
69
133
|
export const FaceCaptureCapturingScreen = forwardRef<
|
|
70
134
|
HTMLDivElement,
|
|
@@ -75,24 +139,49 @@ export const FaceCaptureCapturingScreen = forwardRef<
|
|
|
75
139
|
strings,
|
|
76
140
|
state = 'initiating',
|
|
77
141
|
camera,
|
|
142
|
+
extendTime,
|
|
143
|
+
onExtendTime,
|
|
78
144
|
screenId = 'face-capture-capturing',
|
|
79
145
|
className,
|
|
80
146
|
...rest
|
|
81
147
|
},
|
|
82
148
|
ref,
|
|
83
|
-
) =>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
149
|
+
) => {
|
|
150
|
+
const offer = strings.extendTime;
|
|
151
|
+
// No copy, no notice: a host that has not localized this must not get
|
|
152
|
+
// English, and the flag alone is not permission to invent it.
|
|
153
|
+
const notice =
|
|
154
|
+
extendTime && offer ? (
|
|
155
|
+
<PrizmaSnackbar
|
|
156
|
+
state="neutral"
|
|
157
|
+
isMultiline
|
|
158
|
+
// Assertive on purpose — see the live-region note in this file's
|
|
159
|
+
// header. The component default here would be `status`.
|
|
160
|
+
role="alert"
|
|
161
|
+
linkLabel={offer.linkLabel}
|
|
162
|
+
onLinkClick={onExtendTime}
|
|
163
|
+
>
|
|
164
|
+
<strong>{offer.title}</strong>
|
|
165
|
+
<br />
|
|
166
|
+
{offer.description}
|
|
167
|
+
</PrizmaSnackbar>
|
|
168
|
+
) : undefined;
|
|
169
|
+
|
|
170
|
+
return (
|
|
171
|
+
<PrizmaCaptureScreen
|
|
172
|
+
ref={ref}
|
|
173
|
+
className={className}
|
|
174
|
+
state={SELFIE_STATE[state]}
|
|
175
|
+
camera={camera}
|
|
176
|
+
feedbackText={strings.capturing[state]}
|
|
177
|
+
notice={notice}
|
|
178
|
+
verifiedLabel={strings.verifiedLabel}
|
|
179
|
+
navLabel={strings.navLabel}
|
|
180
|
+
screenId={screenId}
|
|
181
|
+
{...rest}
|
|
182
|
+
/>
|
|
183
|
+
);
|
|
184
|
+
},
|
|
96
185
|
);
|
|
97
186
|
FaceCaptureCapturingScreen.displayName = 'FaceCaptureCapturingScreen';
|
|
98
187
|
|
|
@@ -12,7 +12,72 @@
|
|
|
12
12
|
* inherit all three as correct defaults.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
/*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
|
|
15
|
+
/* The non-status glyph slot this file used to own (`.face-capture-glyph`) was
|
|
16
|
+
* the third byte-identical copy of one pattern, so it moved to
|
|
17
|
+
* `ScreenLayout.css` as `__glyph` — DEVIATIONS #DC-29, closed. */
|
|
18
|
+
|
|
19
|
+
/* ── Short panels: the capture stack moves up, the ring never changes size ───
|
|
20
|
+
* `PrizmaSelfieCapture` is a fixed stack by design: Spacing/40, the 335 stage,
|
|
21
|
+
* Spacing/32, the instruction, and in manual mode another Spacing/32 and the 64
|
|
22
|
+
* shutter, then Spacing/40 — 583 tall on the manual screen, every number
|
|
23
|
+
* measured off the module Figma (DEVIATIONS #12). Under the nav and above the
|
|
24
|
+
* footer's reserve a closed iPhone Duo leaves 513 (678 − 103 − 62, measured
|
|
25
|
+
* 2026-10-14), so the manual stack ran 70 past its column and the shutter
|
|
26
|
+
* landed on the verified tag (shutter 582–646, tag 606–636). The auto-capture
|
|
27
|
+
* screens are 94 shorter and fit the Duo as authored.
|
|
28
|
+
*
|
|
29
|
+
* The RING is not what gives ground. Camila, 2026-10-14: the face frame is the
|
|
30
|
+
* same size on every screen, because the user has to see their face; if it
|
|
31
|
+
* ever had to shrink it would shrink on every capture screen together, and we
|
|
32
|
+
* avoid that. So the stack moves UP instead: the root's Spacing/40 above and
|
|
33
|
+
* below go (the ring sits flush under the nav row, 40 higher than on the
|
|
34
|
+
* reference) and the two Spacing/32 gaps become Spacing/16, which on the
|
|
35
|
+
* manual screen is 112 back — 103 + 334 + 16 + 41 + 16 + 64 = 574, 32 of air
|
|
36
|
+
* above the tag. Instruction and shutter keep their height, the ring its 334.
|
|
37
|
+
*
|
|
38
|
+
* EVERY capture screen takes it, not only the manual one that needed it
|
|
39
|
+
* (Camila, 2026-10-14: "put all face frames at the height that the manual
|
|
40
|
+
* capture one is, so we don't need a jump there"). The ring not moving between
|
|
41
|
+
* screens is the rule Video Selfie's #VS-24 was written for: a capture window
|
|
42
|
+
* that jumps as the step advances reads as a glitch. So on a short panel the
|
|
43
|
+
* whole module's ring is at 103, auto, manual, loading and verdict alike.
|
|
44
|
+
* Outside the query not one declaration exists, so the reference is
|
|
45
|
+
* byte-identical. DEVIATIONS #20. */
|
|
46
|
+
@container pcs-screen (max-height: 720px) {
|
|
47
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture {
|
|
48
|
+
padding-block: 0;
|
|
49
|
+
gap: var(--prizma-spacing-16);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* ── Big panels: the ring grows to the column and the stack moves down ───────
|
|
54
|
+
* The mirror of the block above, and the capture counterpart of the tutorial's
|
|
55
|
+
* #F-36. On the 768 × 1024 iPad the column widens to 468 but the stack kept
|
|
56
|
+
* its 335 ring flush under the nav, so the ring read small (335 in a 420
|
|
57
|
+
* content column, 85px of air either side) and high (its centre at 30% of the
|
|
58
|
+
* panel, where the 390 phone has it at 37%), with 300px of empty column under
|
|
59
|
+
* the instruction (Camila, 2026-10-19: "the face frame too small and way up
|
|
60
|
+
* the screen", on the tablet flow, grid and screen view alike).
|
|
61
|
+
*
|
|
62
|
+
* Two owner decisions, 2026-10-20. The RING GROWS: the 2026-10-14 rule that
|
|
63
|
+
* the ring never changes size was written so it would not SHRINK on a short
|
|
64
|
+
* panel, and on a panel this big the person's face is still what the screen is
|
|
65
|
+
* about, so the stage takes the content column's full measure (420 inside the
|
|
66
|
+
* 468 wide column), the way #F-36 lets the tutorial art grow. Every state
|
|
67
|
+
* grows together (auto, manual, loading, verdict) so the ring still never
|
|
68
|
+
* jumps between steps. The STACK MOVES DOWN BY A FIXED OFFSET, not to the
|
|
69
|
+
* centre: the stack under the ring is a different height on every screen
|
|
70
|
+
* (the manual one carries the shutter), so centring THAT would move the ring
|
|
71
|
+
* between steps, the bug #VS-24 exists for; the same reason Video Selfie's
|
|
72
|
+
* #VS-32 took an offset. Spacing/40 + Spacing/32 above the ring puts its
|
|
73
|
+
* centre at 102 + 72 + 210 = 384, 37.5% of 1024, the reference's own
|
|
74
|
+
* proportion (measured 2026-10-20); the manual screen's shutter ends at 765
|
|
75
|
+
* with the verified tag at 978. Both axes gate it for #F-36's reasons: `min-height: 845px` keeps the
|
|
76
|
+
* 844 reference and every short panel byte-identical, `min-width: 468px` keeps
|
|
77
|
+
* it off phones and foldables where the column stays 390. DEVIATIONS #21. */
|
|
78
|
+
@container pcs-screen ((min-height: 845px) and (min-width: 468px)) {
|
|
79
|
+
.prizma-screen-layout__content--capture > .prizma-selfie-capture {
|
|
80
|
+
max-width: 100%;
|
|
81
|
+
padding-top: calc(var(--prizma-spacing-40) + var(--prizma-spacing-32));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -56,6 +56,30 @@ export interface FaceCaptureStrings {
|
|
|
56
56
|
* `initiating` has no instruction in the design; omit it. */
|
|
57
57
|
capturing: Partial<Record<FaceCaptureCapturingState, string>>;
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* faceCapture.capturing.extendTime — the accessibility offer that rides any
|
|
61
|
+
* capturing state 20 s before auto capture falls back to manual.
|
|
62
|
+
*
|
|
63
|
+
* It exists for WCAG 2.2.1 Timing Adjustable, satisfied through the *Extend*
|
|
64
|
+
* clause: warn before the limit expires, give the user at least 20 s to
|
|
65
|
+
* extend with a simple action, and let them extend at least ten times. The
|
|
66
|
+
* 20 s is that threshold, not a chosen duration — which is why `description`
|
|
67
|
+
* is a whole string and not a number the screen formats: ten locales write
|
|
68
|
+
* that sentence ten different ways, and the count has to live inside it.
|
|
69
|
+
*
|
|
70
|
+
* Shown only when accessibility mode is ON for the flow (a per-flow
|
|
71
|
+
* dashboard setting). With it off, nothing about today's capture changes.
|
|
72
|
+
* Optional for that reason: a host that never turns it on never writes it.
|
|
73
|
+
*/
|
|
74
|
+
extendTime?: {
|
|
75
|
+
/** Bold first line — "Need more time?" */
|
|
76
|
+
title: string;
|
|
77
|
+
/** "Manual capture starts in 20 s" — carries the count, see above. */
|
|
78
|
+
description: string;
|
|
79
|
+
/** The action that keeps the user on auto — "Extend auto-capture". */
|
|
80
|
+
linkLabel: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
59
83
|
/** faceCapture.manualCapture.default */
|
|
60
84
|
manualCapture: {
|
|
61
85
|
/** "Align your face within the silhouette and press the button to capture" */
|
package/src/FormScreen.css
CHANGED
|
@@ -29,6 +29,20 @@
|
|
|
29
29
|
padding-top: var(--pfs-fields-offset, var(--prizma-spacing-32));
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/* ── Field stack pinned to the CTA band ──────────────────────────────────────
|
|
33
|
+
* `fieldsAlign="end"` on `PrizmaFormScreen`. The stack keeps its `flex: 1`
|
|
34
|
+
* column and simply packs its rows at the bottom, so the space between the
|
|
35
|
+
* title block and the first row is what is left over rather than a value
|
|
36
|
+
* anybody declares. The `margin-bottom` is the frame's own Spacing/16 between
|
|
37
|
+
* the card and the Button group (`biometricConsent.empty`, 2001:16361 — the
|
|
38
|
+
* CONTENT column's gap), the same value the scrolling stack uses for the same
|
|
39
|
+
* seam, so the two shapes agree on how far a row sits from Continue. Biometric
|
|
40
|
+
* Consent is the first consumer. DEVIATIONS #BC-1. */
|
|
41
|
+
.prizma-form-screen__fields--end {
|
|
42
|
+
justify-content: flex-end;
|
|
43
|
+
margin-bottom: var(--prizma-spacing-16);
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
/* ── Scrolling field stack ───────────────────────────────────────────────────
|
|
33
47
|
* Screens are authored at 390×844 and never reflow (DEVIATIONS #17), but some
|
|
34
48
|
* Form sections draw a middle column taller than the frame and let it pan:
|
package/src/FormScreen.tsx
CHANGED
|
@@ -62,6 +62,13 @@ export interface PrizmaFormScreenProps
|
|
|
62
62
|
* body text.
|
|
63
63
|
*/
|
|
64
64
|
linkLabel?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Renders `linkLabel` in Core's disabled treatment, for a link that exists
|
|
67
|
+
* but cannot be pressed yet — Phone Input's "Resend code in 30s" while the
|
|
68
|
+
* resend timer runs (Figma `phoneNumber.OTP.typing`, Tertiary / Link ·
|
|
69
|
+
* Disabled).
|
|
70
|
+
*/
|
|
71
|
+
linkDisabled?: boolean;
|
|
65
72
|
/**
|
|
66
73
|
* A composed line below the primary: body copy with inline links, e.g. Phone
|
|
67
74
|
* Input's "Didn't receive the code? **Resend code** or **Change phone
|
|
@@ -98,6 +105,27 @@ export interface PrizmaFormScreenProps
|
|
|
98
105
|
* eKYB, Data Sharing Consent); it is the archetype's now. DEVIATIONS #DSC-2.
|
|
99
106
|
*/
|
|
100
107
|
scrollFields?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Where the field stack sits in the column when it is SHORTER than the
|
|
110
|
+
* space it has. `start` (the default) hangs it off the title block, which is
|
|
111
|
+
* every form so far. `end` pins it to the CTA band instead, leaving the space
|
|
112
|
+
* between the title and the stack empty — Biometric Consent's section draws
|
|
113
|
+
* exactly that: a `justify-between` middle with the Title at the top and the
|
|
114
|
+
* one consent card flush against Continue, Spacing/16 above it
|
|
115
|
+
* (`biometricConsent.empty`, 2001:16361). Selected here so the module
|
|
116
|
+
* declares no layout of its own; the rule lives once in `FormScreen.css`.
|
|
117
|
+
* DEVIATIONS #BC-1.
|
|
118
|
+
*/
|
|
119
|
+
fieldsAlign?: 'start' | 'end';
|
|
120
|
+
/**
|
|
121
|
+
* A shell-level layer painted OVER the whole screen — the same slot archetype
|
|
122
|
+
* A carries for Document Capture's method sheet (#F-32, #DC-30): a scrim plus
|
|
123
|
+
* Core's `PrizmaBottomSheetContent` or `PrizmaModalContent`, presented on top
|
|
124
|
+
* of the dimmed form. It cannot ride in the content column: it is absolutely
|
|
125
|
+
* positioned against the shell. Biometric Consent's quit confirmation is the
|
|
126
|
+
* first Form consumer (DEVIATIONS #BC-8).
|
|
127
|
+
*/
|
|
128
|
+
overlay?: ReactNode;
|
|
101
129
|
/**
|
|
102
130
|
* Let the field stack change SHAPE on a wide screen: `PrizmaFormRow` pairs
|
|
103
131
|
* become two lanes and Continue + Back share a row, once the shell's own
|
|
@@ -140,12 +168,15 @@ export const PrizmaFormScreen = forwardRef<HTMLDivElement, PrizmaFormScreenProps
|
|
|
140
168
|
ctaLoading = false,
|
|
141
169
|
ctaLoadingLabel,
|
|
142
170
|
linkLabel,
|
|
171
|
+
linkDisabled,
|
|
143
172
|
linkContent,
|
|
144
173
|
verifiedLabel,
|
|
145
174
|
children,
|
|
146
175
|
fieldsOffset,
|
|
147
176
|
fieldsGap,
|
|
148
177
|
scrollFields = false,
|
|
178
|
+
fieldsAlign = 'start',
|
|
179
|
+
overlay,
|
|
149
180
|
responsive = false,
|
|
150
181
|
navLabel,
|
|
151
182
|
screenId,
|
|
@@ -179,6 +210,7 @@ export const PrizmaFormScreen = forwardRef<HTMLDivElement, PrizmaFormScreenProps
|
|
|
179
210
|
className={[
|
|
180
211
|
'prizma-form-screen__fields',
|
|
181
212
|
scrollFields ? 'prizma-form-screen__fields--scroll' : null,
|
|
213
|
+
fieldsAlign === 'end' ? 'prizma-form-screen__fields--end' : null,
|
|
182
214
|
]
|
|
183
215
|
.filter(Boolean)
|
|
184
216
|
.join(' ')}
|
|
@@ -217,6 +249,7 @@ export const PrizmaFormScreen = forwardRef<HTMLDivElement, PrizmaFormScreenProps
|
|
|
217
249
|
<PrizmaButton
|
|
218
250
|
variant="tertiary-link"
|
|
219
251
|
size="L"
|
|
252
|
+
disabled={linkDisabled}
|
|
220
253
|
onClick={() => onAction?.({ type: 'secondary', screenId })}
|
|
221
254
|
>
|
|
222
255
|
{linkLabel}
|
|
@@ -231,6 +264,7 @@ export const PrizmaFormScreen = forwardRef<HTMLDivElement, PrizmaFormScreenProps
|
|
|
231
264
|
</div>
|
|
232
265
|
) : null}
|
|
233
266
|
</div>
|
|
267
|
+
{overlay}
|
|
234
268
|
</PrizmaScreenShell>
|
|
235
269
|
),
|
|
236
270
|
);
|
package/src/IdCaptureLayout.css
CHANGED
|
@@ -99,12 +99,89 @@
|
|
|
99
99
|
flex-basis: calc((100cqw - 2 * var(--prizma-spacing-24)) * 420 / 306);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/* ── A notice on the stage: the horizontal frame may give up height too ──────
|
|
103
|
+
* The "Need more time?" offer (`.id-capture-stage__notice`, IDC-32) adds ~90px
|
|
104
|
+
* of content to the bottom band. On the 390 × 844 reference the band has the
|
|
105
|
+
* room and nothing moves. On a short panel it does not: measured 2026-10-15,
|
|
106
|
+
* the horizontal ID frame is aspect-locked and does not shrink, so the column
|
|
107
|
+
* overflowed and the notice ran 10px into the help strip at 320 × 693 and 36px
|
|
108
|
+
* at the closed iPhone Duo (466 × 678). The same recipe as the vertical rule
|
|
109
|
+
* above, applied to the horizontal frames ONLY while a notice is on the stage:
|
|
110
|
+
* the frame starts at its full-width height and gives up height when the
|
|
111
|
+
* column is short, the aspect ratio narrows it to match, the title band keeps
|
|
112
|
+
* its content height. Face Capture makes the identical trade at 320 (its
|
|
113
|
+
* selfie frame gives up Spacing/40 for the notice, ScreenLayout.css) and the
|
|
114
|
+
* owner's rule is explicit that the frame may get smaller (2026-08-18). A
|
|
115
|
+
* stage without a notice is untouched. */
|
|
116
|
+
.prizma-viewfinder__content:has(> .id-capture-band > .id-capture-stage__notice) {
|
|
117
|
+
min-height: 0;
|
|
118
|
+
}
|
|
119
|
+
.prizma-viewfinder__content:has(> .id-capture-band > .id-capture-stage__notice) > .id-capture-band--top {
|
|
120
|
+
flex-shrink: 0;
|
|
121
|
+
min-height: min-content;
|
|
122
|
+
}
|
|
123
|
+
.prizma-viewfinder__content:has(> .id-capture-band > .id-capture-stage__notice) > .prizma-id-capture--horizontal:not(.prizma-id-capture--poa) {
|
|
124
|
+
flex: 0 1 auto;
|
|
125
|
+
min-height: 0;
|
|
126
|
+
}
|
|
127
|
+
.prizma-viewfinder__content:has(> .id-capture-band > .id-capture-stage__notice) > .prizma-id-capture--horizontal:not(.prizma-id-capture--poa) .prizma-id-capture__frame {
|
|
128
|
+
flex: 0 1 auto;
|
|
129
|
+
min-height: 0;
|
|
130
|
+
width: auto;
|
|
131
|
+
max-width: 100%;
|
|
132
|
+
flex-basis: calc((100cqw - 2 * var(--prizma-spacing-24)) * 220 / 350);
|
|
133
|
+
}
|
|
134
|
+
.prizma-viewfinder__content:has(> .id-capture-band > .id-capture-stage__notice) > .prizma-id-capture--passport.prizma-id-capture--horizontal .prizma-id-capture__frame {
|
|
135
|
+
flex-basis: calc((100cqw - 2 * var(--prizma-spacing-24)) * 254 / 350);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* ── Short panels: the tutorial art is sized by its halo, not its canvas ─────
|
|
139
|
+
* `PrizmaIllustrationIdTutorial` is a 342 × 392 canvas with the halo centred
|
|
140
|
+
* at r130 (y 66–326) and the hand-and-document artwork inside it (y 100–313;
|
|
141
|
+
* the passport's hand fades out above). The 66 above and below the halo are
|
|
142
|
+
* air at rest; the bottom band is where the hand travels in from during the
|
|
143
|
+
* loop. The selfie illustration is a 296 canvas with the same r130 halo and 18
|
|
144
|
+
* of air: on the 844 reference both halos are 260 and the two tutorials match.
|
|
145
|
+
*
|
|
146
|
+
* On a short panel the tutorial middle is height-limited (ScreenLayout.css,
|
|
147
|
+
* #F-35) and the two canvases scale by height, so the ID halo comes out 18 %
|
|
148
|
+
* smaller than the selfie's (170 vs 209 on the closed iPhone Duo, measured
|
|
149
|
+
* 2026-10-14; Camila: "ID tutorials have illustration a bit too small, no?
|
|
150
|
+
* Compared to the size on the selfie tutorial one"). Fixed by cropping the
|
|
151
|
+
* canvas to the halo band plus Spacing/16 on each side — y 50 to 342, 292
|
|
152
|
+
* units, the same 89 % the selfie's halo takes of its own box — so the halo
|
|
153
|
+
* fills the slot the way the selfie's does. The wrapper takes the slot and
|
|
154
|
+
* clips; the svg is scaled so 292 of its 392 units fill the wrapper and
|
|
155
|
+
* centres, so the crop is symmetric around the halo and the halo's centre
|
|
156
|
+
* does not move. During the loop the entering hand is clipped 50 units
|
|
157
|
+
* earlier than the canvas clips it, which is invisible against the fade.
|
|
158
|
+
* Outside the query nothing exists: the reference renders the full canvas.
|
|
159
|
+
* DEVIATIONS #IDC-31. */
|
|
160
|
+
@container pcs-screen (max-height: 720px) {
|
|
161
|
+
.prizma-screen-layout__flex > .prizma-illustration-tutorial {
|
|
162
|
+
flex: 1 1 0;
|
|
163
|
+
min-height: 0;
|
|
164
|
+
align-self: stretch;
|
|
165
|
+
display: flex;
|
|
166
|
+
align-items: center;
|
|
167
|
+
justify-content: center;
|
|
168
|
+
overflow: hidden;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.prizma-screen-layout__flex > .prizma-illustration-tutorial > svg {
|
|
172
|
+
flex: none;
|
|
173
|
+
height: calc(100% * 392 / 292);
|
|
174
|
+
width: auto;
|
|
175
|
+
max-width: none;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
102
179
|
/* ── Camera stage (dark) ───────────────────────────────────────────────────── */
|
|
103
180
|
|
|
104
181
|
/* The stage's nav row carries only the close X (no logo — the camera owns the
|
|
105
182
|
* screen). The foundation `.prizma-screen-nav` supplies the status-bar reserve,
|
|
106
183
|
* the 44px flow slot and the un-fixing of Core's PrizmaNavigation; the ink is
|
|
107
|
-
* the only thing the camera stage changes: Core's nav icon is the
|
|
184
|
+
* the only thing the camera stage changes: Core's nav icon is the themed
|
|
108
185
|
* `Icon/Neutral/500`, which disappears on the always-dark camera surface, so it
|
|
109
186
|
* takes the camera's own Static ink — the same token PrizmaCaptureManual uses
|
|
110
187
|
* for the shutter and the "?" help control. DEVIATIONS.md #IDC-21. */
|
|
@@ -118,6 +195,44 @@
|
|
|
118
195
|
width: 100%;
|
|
119
196
|
}
|
|
120
197
|
|
|
198
|
+
/* ── The "Need more time?" notice ─────────────────────────────────────────────
|
|
199
|
+
* The Snackbar the stage raises 20 s before auto-capture falls back to the
|
|
200
|
+
* shutter (IdCaptureStageScreen `extendTime`, 2026-10-15). It takes the BOTTOM
|
|
201
|
+
* band — the air between the encrypted row and the strip's reserved space —
|
|
202
|
+
* because, unlike Face Capture, this stage's strip is never empty: the "?" help
|
|
203
|
+
* control rides it on every stage (IDC-29), so the shared rail the selfie notice
|
|
204
|
+
* uses (`.prizma-screen-layout__capture-notice`) would land on top of it.
|
|
205
|
+
*
|
|
206
|
+
* The band is `justify-content: flex-end`, so the notice sits just above the
|
|
207
|
+
* strip's Spacing/12 of breathing and the frame above does not move when the
|
|
208
|
+
* offer arrives. The band is also `flex: 1; min-height: 0`, which on a short
|
|
209
|
+
* panel would let it shrink to nothing and spill the notice upward over the
|
|
210
|
+
* encrypted row; with a notice in it the band keeps its content height and the
|
|
211
|
+
* shortfall goes where this stylesheet already sends it — the vertical frame
|
|
212
|
+
* (the short-panel rule above), which the owner has said may get smaller
|
|
213
|
+
* (2026-08-18). DEVIATIONS #IDC-32. */
|
|
214
|
+
.id-capture-band:has(> .id-capture-stage__notice) {
|
|
215
|
+
flex-shrink: 0;
|
|
216
|
+
min-height: min-content;
|
|
217
|
+
padding-top: var(--prizma-spacing-16);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.id-capture-stage__notice {
|
|
221
|
+
display: flex;
|
|
222
|
+
/* The HUD column centres its copy; the Snackbar's own text is left-set. */
|
|
223
|
+
text-align: left;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/* On a 320 phone the notice drops its status glyph — the same call Face
|
|
227
|
+
* Capture made (Camila, 2026-10-05, ScreenLayout.css): 44 of the 272px column
|
|
228
|
+
* on a decorative mark pushed the body to four lines. The icon is
|
|
229
|
+
* `aria-hidden`; the copy carries the meaning without it. */
|
|
230
|
+
@container pcs-screen (max-width: 340px) {
|
|
231
|
+
.id-capture-stage__notice .prizma-snackbar__icon {
|
|
232
|
+
display: none;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
121
236
|
/* The feedback pill replaces the title block on the error stages (Figma
|
|
122
237
|
* `1-5-5 … 1-5-9-id-errors`): same band, same Spacing/40 above the frame. */
|
|
123
238
|
.id-capture-stage__feedback {
|
|
@@ -125,6 +240,54 @@
|
|
|
125
240
|
justify-content: center;
|
|
126
241
|
}
|
|
127
242
|
|
|
243
|
+
/* ── Short or narrow panels: the live cue takes Template B ───────────────────
|
|
244
|
+
* `PrizmaCaptureFeedback` ships two templates on its `showAnimation` axis:
|
|
245
|
+
* A, the 120-ish pill with the illustration and a Headline/H3 title, and B, a
|
|
246
|
+
* 72 pill with no illustration and Headline/H5. The error stages draw A on the
|
|
247
|
+
* 390 × 844 reference. On a closed iPhone Duo (678) A still fits — measured
|
|
248
|
+
* 2026-10-14, the frame lands at 198–473 with the pill above it — but it is
|
|
249
|
+
* the tallest element on a stage that has just lost 166px, and on a 640 phone
|
|
250
|
+
* or a 320 column it does not fit at all. Video Selfie already made this call
|
|
251
|
+
* for its own cues (DEVIATIONS #VS-30, Camila 2026-10-07): under 340 wide or
|
|
252
|
+
* 720 tall the pill is B. The same line here, so the two camera modules agree
|
|
253
|
+
* on when a cue goes compact. Nothing is re-skinned: fill, radius, stroke and
|
|
254
|
+
* shadow are Core's and identical between A and B (capture-feedback.md §4.4);
|
|
255
|
+
* what changes is exactly Template B's four switches, taken from
|
|
256
|
+
* `CaptureFeedback.css`'s own `--compact` modifier.
|
|
257
|
+
*
|
|
258
|
+
* A container query, not the prop: the screen cannot know the panel's height,
|
|
259
|
+
* the shell's `pcs-screen` container can. ONE `or` condition, not two
|
|
260
|
+
* comma-separated queries (lightningcss rejects the latter; see
|
|
261
|
+
* VideoSelfieLayout.css). The 390 reference is unchanged. DEVIATIONS #IDC-30. */
|
|
262
|
+
@container pcs-screen ((max-width: 340px) or (max-height: 720px)) {
|
|
263
|
+
.id-capture-stage__feedback .prizma-capture-feedback__illustration {
|
|
264
|
+
display: none;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* Template B: body padding-bottom 12 → 16, itemSpacing 8 → 4. */
|
|
268
|
+
.id-capture-stage__feedback .prizma-capture-feedback__body {
|
|
269
|
+
padding: var(--prizma-spacing-16) 0;
|
|
270
|
+
gap: var(--prizma-spacing-4);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/* Title Headline/H3 → Headline/H5. */
|
|
274
|
+
.id-capture-stage__feedback .prizma-capture-feedback__title {
|
|
275
|
+
font-weight: var(--prizma-headline-h5-font-weight);
|
|
276
|
+
font-size: var(--prizma-headline-h5-font-size);
|
|
277
|
+
line-height: var(--prizma-headline-h5-line-height);
|
|
278
|
+
letter-spacing: var(--prizma-headline-h5-letter-spacing);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* Subtitle Headline/H5 → Body/M Regular. */
|
|
282
|
+
.id-capture-stage__feedback .prizma-capture-feedback__subtitle {
|
|
283
|
+
font-family: var(--prizma-body-family);
|
|
284
|
+
font-weight: var(--prizma-body-m-regular-font-weight);
|
|
285
|
+
font-size: var(--prizma-body-m-regular-font-size);
|
|
286
|
+
line-height: var(--prizma-body-m-regular-line-height);
|
|
287
|
+
letter-spacing: var(--prizma-body-m-regular-letter-spacing);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
128
291
|
/* ── Removed: promoted into the foundation ───────────────────────────────────
|
|
129
292
|
* `.id-capture-glyph*` (the non-status glyph slot) is now
|
|
130
293
|
* `ScreenLayout.css`'s `__glyph` — DEVIATIONS #DC-29, closed.
|
|
@@ -142,7 +305,7 @@
|
|
|
142
305
|
*
|
|
143
306
|
* The plate needs no override — Core's own `mode="overlay"` already makes the
|
|
144
307
|
* window transparent, which is what the light screens want. The ink does: the
|
|
145
|
-
* row is re-inked with the
|
|
308
|
+
* row is re-inked with the themed body token so it also survives dark mode,
|
|
146
309
|
* scoped to the light screens only (the camera stage keeps Core's Static white).
|
|
147
310
|
* Core gap — PrizmaIdCapture has no surface-aware encrypted row. DEVIATIONS.md #IDC-28.
|
|
148
311
|
*/
|