@sekyro/elements 0.0.0-stage → 0.1.0-rc.0

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 (123) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE +29 -0
  3. package/README.md +247 -2
  4. package/custom-elements.json +355 -0
  5. package/dist/cdn/chunks/background-monitor-GCMNCJMG-UXYQ5GX7.js +1 -0
  6. package/dist/cdn/chunks/camera-trait-HVV5ZEDI-JB4HN6S3.js +1 -0
  7. package/dist/cdn/chunks/capture-session-doc-K6LVXAGQ-SY3B27LY.js +1 -0
  8. package/dist/cdn/chunks/chunk-2SENV5CV.js +1 -0
  9. package/dist/cdn/chunks/chunk-2ZVKLBJD.js +14 -0
  10. package/dist/cdn/chunks/chunk-3KIFGAEK.js +1 -0
  11. package/dist/cdn/chunks/chunk-3VYQXVW4.js +1 -0
  12. package/dist/cdn/chunks/chunk-4FHWXBOB.js +1 -0
  13. package/dist/cdn/chunks/chunk-562ANROG.js +1 -0
  14. package/dist/cdn/chunks/chunk-6MEPT5ZS.js +1 -0
  15. package/dist/cdn/chunks/chunk-7HJH5Q4M.js +1 -0
  16. package/dist/cdn/chunks/chunk-7XAIG23G.js +1 -0
  17. package/dist/cdn/chunks/chunk-C66GZ7NN.js +1 -0
  18. package/dist/cdn/chunks/chunk-CMDITVXF.js +1 -0
  19. package/dist/cdn/chunks/chunk-CMS5FVGM.js +1 -0
  20. package/dist/cdn/chunks/chunk-D334IAZJ.js +1 -0
  21. package/dist/cdn/chunks/chunk-ET7NCKUV.js +1 -0
  22. package/dist/cdn/chunks/chunk-FAIDO3QL.js +1 -0
  23. package/dist/cdn/chunks/chunk-HDJ6JFXX.js +1 -0
  24. package/dist/cdn/chunks/chunk-HODE7UDG.js +1 -0
  25. package/dist/cdn/chunks/chunk-IBOJTLL7.js +1 -0
  26. package/dist/cdn/chunks/chunk-IFGPCCJH.js +1 -0
  27. package/dist/cdn/chunks/chunk-JM3CYFFZ.js +1 -0
  28. package/dist/cdn/chunks/chunk-JOZCJGRV.js +1 -0
  29. package/dist/cdn/chunks/chunk-KPGTFHQU.js +1 -0
  30. package/dist/cdn/chunks/chunk-OBPBHX2J.js +1 -0
  31. package/dist/cdn/chunks/chunk-OIJVTJML.js +1 -0
  32. package/dist/cdn/chunks/chunk-RK4HVNRS.js +1 -0
  33. package/dist/cdn/chunks/chunk-RRLXNT33.js +1 -0
  34. package/dist/cdn/chunks/chunk-SK6UAYX2.js +1 -0
  35. package/dist/cdn/chunks/chunk-T4M2J44L.js +1 -0
  36. package/dist/cdn/chunks/chunk-TCW6XNLI.js +1 -0
  37. package/dist/cdn/chunks/chunk-UYAVCSQ4.js +25 -0
  38. package/dist/cdn/chunks/chunk-UZWMCNZI.js +1 -0
  39. package/dist/cdn/chunks/chunk-X767DBO7.js +1 -0
  40. package/dist/cdn/chunks/chunk-XYQGAQBQ.js +1 -0
  41. package/dist/cdn/chunks/chunk-YEPHU5PX.js +1 -0
  42. package/dist/cdn/chunks/chunk-YMGCOMYZ.js +1 -0
  43. package/dist/cdn/chunks/chunk-Z3EEB4CI.js +1 -0
  44. package/dist/cdn/chunks/chunk-ZKEOHGBY.js +33 -0
  45. package/dist/cdn/chunks/clip-inspect-HZ7N2YOP-DCDXB76T.js +1 -0
  46. package/dist/cdn/chunks/create-document-capture-LNX6NFSK-A4LP25Y5.js +1 -0
  47. package/dist/cdn/chunks/create-portrait-capture-VRZZOMJS-I4FBRNBP.js +1 -0
  48. package/dist/cdn/chunks/detector-scanic-F3Y5X3DF-FGVR4NEM.js +1 -0
  49. package/dist/cdn/chunks/document-capture-view-JIKJWCFG-MMCEL43X.js +1 -0
  50. package/dist/cdn/chunks/eid-view-IW2ZP2NG-EB5SCHBD.js +1 -0
  51. package/dist/cdn/chunks/email-otp-view-VDTMZ4R5-Y5QHQDIB.js +1 -0
  52. package/dist/cdn/chunks/flow-views-N4FMOYIR-FDN6ATHN.js +1 -0
  53. package/dist/cdn/chunks/icao-gate-SO6YJ7RV-MPW6W3QN.js +1 -0
  54. package/dist/cdn/chunks/icao-tuning-DCZCMCEQ-ZQSK7ZOV.js +1 -0
  55. package/dist/cdn/chunks/keyframe-rank-R4NPQGN3-VRURE6OQ.js +1 -0
  56. package/dist/cdn/chunks/landmarker-3BBP3RBY-DDXMOLGK.js +1 -0
  57. package/dist/cdn/chunks/mrz-band-DCXFWDBD-OPMO6HYS.js +1 -0
  58. package/dist/cdn/chunks/overlay-de-F7GCMCGJ-FBTP3BSM.js +1 -0
  59. package/dist/cdn/chunks/overlay-es-HIO7CIKS-GDHVHUQW.js +1 -0
  60. package/dist/cdn/chunks/overlay-pt-YC4HRHKL-J3TGRZRW.js +1 -0
  61. package/dist/cdn/chunks/plan-runner-DIRERYBF-FANNXQNO.js +1 -0
  62. package/dist/cdn/chunks/portrait-capture-view-LWESDZPM-SEOHMLJQ.js +1 -0
  63. package/dist/cdn/chunks/portrait-review-view-FU3QSO4K-DZHDIMQX.js +1 -0
  64. package/dist/cdn/chunks/print-4WOMNRBE-DNXJ7ERA.js +11 -0
  65. package/dist/cdn/chunks/scanic-ml-stub-XPNKT2N3-YSXFN7KY.js +1 -0
  66. package/dist/cdn/chunks/segmenter-3CVPTZMM-WGI6XGWN.js +1 -0
  67. package/dist/cdn/chunks/turnstile-N4K4U2AI-SLP55XAA.js +1 -0
  68. package/dist/cdn/chunks/upload-file-C4MFKLT3-DXCNEDXP.js +1 -0
  69. package/dist/cdn/chunks/vision_bundle-WBHR7TEE.js +41 -0
  70. package/dist/cdn/define.js +1 -0
  71. package/dist/cdn/index.js +1 -0
  72. package/dist/chunk-43YHL2WG.js +1 -0
  73. package/dist/chunk-4QI2LTJD.js +1 -0
  74. package/dist/chunk-73JRPFCO.js +33 -0
  75. package/dist/chunk-HSQWGTF7.js +1 -0
  76. package/dist/chunk-JJNFGW3A.js +25 -0
  77. package/dist/chunk-JQ3ANVKN.js +1 -0
  78. package/dist/chunk-KU4DZ3OQ.js +1 -0
  79. package/dist/chunk-OSBGOI4W.js +14 -0
  80. package/dist/chunk-RPLVIGTS.js +1 -0
  81. package/dist/chunk-SEE6MST7.js +1 -0
  82. package/dist/chunk-TPIBYY2S.js +1 -0
  83. package/dist/chunk-UT2KIR2K.js +1 -0
  84. package/dist/chunk-W2UTL5PI.js +1 -0
  85. package/dist/chunk-WWGJDMZQ.js +1 -0
  86. package/dist/chunk-X5K27NXI.js +1 -0
  87. package/dist/chunk-X5WMOOH2.js +1 -0
  88. package/dist/define.cjs +66 -0
  89. package/dist/define.d.cts +7 -0
  90. package/dist/define.d.ts +7 -0
  91. package/dist/define.js +1 -0
  92. package/dist/document-capture-view-JIKJWCFG-OWMTF5A3.js +1 -0
  93. package/dist/eid-view-IW2ZP2NG-SKEYTRTX.js +1 -0
  94. package/dist/email-otp-view-VDTMZ4R5-EO7T6SL4.js +1 -0
  95. package/dist/flow-views-N4FMOYIR-J54ADNRO.js +1 -0
  96. package/dist/fonts/Cairo-OFL.txt +93 -0
  97. package/dist/fonts/Geist-OFL.txt +93 -0
  98. package/dist/fonts/Inter-OFL.txt +93 -0
  99. package/dist/fonts/SekyroCairo-Bold.woff2 +0 -0
  100. package/dist/fonts/SekyroCairo-Regular.woff2 +0 -0
  101. package/dist/fonts/SekyroCairo-SemiBold.woff2 +0 -0
  102. package/dist/fonts/SekyroGeist-Bold.woff2 +0 -0
  103. package/dist/fonts/SekyroGeist-SemiBold.woff2 +0 -0
  104. package/dist/fonts/SekyroInter-Medium.woff2 +0 -0
  105. package/dist/fonts/SekyroInter-Regular.woff2 +0 -0
  106. package/dist/fonts/SekyroInter-SemiBold.woff2 +0 -0
  107. package/dist/index.cjs +66 -0
  108. package/dist/index.d.cts +1099 -0
  109. package/dist/index.d.ts +1099 -0
  110. package/dist/index.js +1 -0
  111. package/dist/overlay-de-F7GCMCGJ-7OI7SGX4.js +1 -0
  112. package/dist/overlay-es-HIO7CIKS-LXC2SFGY.js +1 -0
  113. package/dist/overlay-pt-YC4HRHKL-2QCRICEV.js +1 -0
  114. package/dist/portrait-capture-view-LWESDZPM-XZOM6LXG.js +1 -0
  115. package/dist/portrait-review-view-FU3QSO4K-AGWEX2EQ.js +1 -0
  116. package/dist/styles.css +1475 -0
  117. package/package.json +117 -4
  118. package/sbom.cdx.json +153 -0
  119. package/types/empty.js +2 -0
  120. package/types/events.d.ts +9 -0
  121. package/types/jsx.d.ts +15 -0
  122. package/types/svelte.d.ts +16 -0
  123. package/types/vue.d.ts +15 -0
@@ -0,0 +1,1475 @@
1
+ /* @sekyro/react — plain CSS, logical properties only (ar/fr: RTL for free).
2
+ * Every painted color goes through a `--sekyro-*` token; the literal defaults
3
+ * below are the ONLY hex values in this file (scripts/check-css.mjs enforces
4
+ * both rules). They are the Sekyro AI brand (DEFAULT_THEME, from @sekyro/brand).
5
+ * SekyroThemeProvider overrides the tokens on `.sekyro-root`. */
6
+ :root {
7
+ --sekyro-color-brand: #0d3b66;
8
+ --sekyro-color-brand-fg: #ffffff;
9
+ --sekyro-color-fg: #13141f;
10
+ --sekyro-color-fg-muted: #4e5270;
11
+ --sekyro-color-bg: #f6f7fb;
12
+ --sekyro-color-surface: #ffffff;
13
+ --sekyro-color-ring: #0d3b66;
14
+ --sekyro-color-danger: #ca0f07;
15
+ --sekyro-color-success: #007a5e;
16
+ --sekyro-color-warning: #735003;
17
+ --sekyro-radius: 16px;
18
+ --sekyro-font: "Sekyro Inter", Inter, system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans Arabic", "Noto Sans", sans-serif;
19
+ }
20
+
21
+ .sekyro-root {
22
+ font-family: var(--sekyro-font);
23
+ color: var(--sekyro-color-fg);
24
+ }
25
+
26
+ /* ── layout ────────────────────────────────────────────────────────────── */
27
+ .sekyro-capture {
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: 1.5rem;
31
+ font-family: var(--sekyro-font);
32
+ color: var(--sekyro-color-fg);
33
+ box-sizing: border-box;
34
+ }
35
+ .sekyro-capture *,
36
+ .sekyro-capture *::before,
37
+ .sekyro-capture *::after {
38
+ box-sizing: inherit;
39
+ }
40
+ .sekyro-stack {
41
+ display: flex;
42
+ flex-direction: column;
43
+ }
44
+ .sekyro-stack--1 {
45
+ gap: 0.25rem;
46
+ }
47
+ .sekyro-stack--3 {
48
+ gap: 0.75rem;
49
+ }
50
+ .sekyro-stack--4 {
51
+ gap: 1rem;
52
+ }
53
+ .sekyro-hidden {
54
+ display: none;
55
+ }
56
+ .sekyro-text-body {
57
+ margin: 0;
58
+ font-size: 1rem;
59
+ line-height: 1.5;
60
+ color: var(--sekyro-color-fg);
61
+ }
62
+ /* Secondary text only (notes, hints) — never essential instructions. */
63
+ .sekyro-text-muted {
64
+ margin: 0;
65
+ font-size: 0.875rem;
66
+ line-height: 1.45;
67
+ color: var(--sekyro-color-fg-muted);
68
+ }
69
+ .sekyro-coaching {
70
+ margin: 0;
71
+ padding-inline-start: 1.25rem;
72
+ list-style: disc;
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: 0.25rem;
76
+ font-size: 0.9375rem;
77
+ line-height: 1.45;
78
+ color: var(--sekyro-color-fg);
79
+ }
80
+
81
+ /* ── button ────────────────────────────────────────────────────────────── */
82
+ .sekyro-btn {
83
+ display: inline-flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ gap: 0.5rem;
87
+ min-height: 48px;
88
+ min-width: 48px;
89
+ padding-block: 0.625rem;
90
+ padding-inline: 1.25rem;
91
+ border-radius: var(--sekyro-radius);
92
+ border: 1px solid transparent;
93
+ font: inherit;
94
+ font-size: 1rem;
95
+ font-weight: 600;
96
+ line-height: 1.25;
97
+ cursor: pointer;
98
+ text-align: center;
99
+ -webkit-tap-highlight-color: transparent;
100
+ }
101
+ .sekyro-btn:focus-visible {
102
+ outline: 3px solid var(--sekyro-color-ring);
103
+ outline-offset: 2px;
104
+ }
105
+ .sekyro-btn:disabled,
106
+ .sekyro-btn[aria-disabled="true"] {
107
+ cursor: default;
108
+ opacity: 0.6;
109
+ }
110
+ /* Large bold text (≥ 18.66px / 700): the label reaches WCAG AAA at 4.5:1 on
111
+ * `brand`, so partner themes with an AA-only brand pair still pass 1.4.6. */
112
+ .sekyro-btn--primary {
113
+ background: var(--sekyro-color-brand);
114
+ color: var(--sekyro-color-brand-fg);
115
+ font-size: 1.1875rem;
116
+ font-weight: 700;
117
+ }
118
+ /* Hover darkens THROUGH the tokens (brand → fg), so the label's contrast can
119
+ * only rise; a brightness filter would also dim the label itself. */
120
+ .sekyro-btn--primary:hover {
121
+ background: color-mix(in srgb, var(--sekyro-color-brand) 92%, var(--sekyro-color-fg));
122
+ }
123
+ /* An aria-disabled (still focusable) primary does not react to hover. */
124
+ .sekyro-btn--primary[aria-disabled="true"]:hover {
125
+ background: var(--sekyro-color-brand);
126
+ }
127
+ .sekyro-btn--ghost {
128
+ background: transparent;
129
+ color: var(--sekyro-color-fg);
130
+ border-color: color-mix(in srgb, var(--sekyro-color-fg) 30%, transparent);
131
+ }
132
+ .sekyro-btn--ghost:hover {
133
+ background: color-mix(in srgb, var(--sekyro-color-fg) 6%, transparent);
134
+ }
135
+ /* 48px round on-video icon chip (surface glyph on the fg scrim). */
136
+ .sekyro-btn--chip {
137
+ width: 48px;
138
+ height: 48px;
139
+ padding: 0;
140
+ border: 0;
141
+ border-radius: 9999px;
142
+ background: color-mix(in srgb, var(--sekyro-color-fg) 70%, transparent);
143
+ color: var(--sekyro-color-surface);
144
+ }
145
+ .sekyro-btn--chip:hover {
146
+ background: color-mix(in srgb, var(--sekyro-color-fg) 80%, transparent);
147
+ }
148
+ .sekyro-btn--chip:focus-visible {
149
+ /* On the dark scrim the surface color is the high-contrast ring. */
150
+ outline-color: var(--sekyro-color-surface);
151
+ }
152
+ /* Spec 2026-11-06 §3.3: the capture mode switch, the chip widened to its icon and short label. */
153
+ .sekyro-btn--chip.sekyro-stage__mode-switch {
154
+ display: inline-flex;
155
+ align-items: center;
156
+ gap: 0.5rem;
157
+ width: auto;
158
+ min-height: 48px;
159
+ height: auto;
160
+ max-inline-size: calc(100% - 1.5rem);
161
+ padding-block: 0.5rem;
162
+ padding-inline: 0.75rem 1rem;
163
+ text-align: start;
164
+ }
165
+ .sekyro-btn--full {
166
+ width: 100%;
167
+ }
168
+ .sekyro-btn--start {
169
+ align-self: flex-start;
170
+ }
171
+ .sekyro-icon {
172
+ width: 1.25rem;
173
+ height: 1.25rem;
174
+ margin-inline: auto;
175
+ }
176
+ .sekyro-icon--sm {
177
+ width: 1rem;
178
+ height: 1rem;
179
+ flex-shrink: 0;
180
+ margin-inline: 0;
181
+ }
182
+
183
+ /* ── notice ────────────────────────────────────────────────────────────── */
184
+ .sekyro-notice {
185
+ display: flex;
186
+ flex-direction: column;
187
+ gap: 0.5rem;
188
+ padding: 0.75rem;
189
+ border: 1px solid;
190
+ border-radius: var(--sekyro-radius);
191
+ font-size: 0.9375rem;
192
+ line-height: 1.45;
193
+ color: var(--sekyro-color-fg);
194
+ }
195
+ .sekyro-notice--info {
196
+ border-color: var(--sekyro-color-brand);
197
+ background: color-mix(in srgb, var(--sekyro-color-brand) 8%, var(--sekyro-color-surface));
198
+ }
199
+ .sekyro-notice--warning {
200
+ border-color: var(--sekyro-color-warning);
201
+ background: color-mix(in srgb, var(--sekyro-color-warning) 10%, var(--sekyro-color-surface));
202
+ }
203
+ .sekyro-notice--danger {
204
+ border-color: var(--sekyro-color-danger);
205
+ background: color-mix(in srgb, var(--sekyro-color-danger) 8%, var(--sekyro-color-surface));
206
+ }
207
+
208
+ /* ── capture stage ─────────────────────────────────────────────────────── */
209
+ /* Easing vars are SCOPED to the stage so they never leak into the host. */
210
+ .sekyro-stage {
211
+ --sekyro-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
212
+ --sekyro-ease-settle: cubic-bezier(0.34, 1.56, 0.64, 1);
213
+ position: relative;
214
+ margin-inline: auto;
215
+ aspect-ratio: 3 / 4;
216
+ width: 100%;
217
+ max-width: 24rem;
218
+ overflow: hidden;
219
+ border-radius: var(--sekyro-radius);
220
+ background: var(--sekyro-color-fg);
221
+ }
222
+ .sekyro-stage__video {
223
+ position: absolute;
224
+ inset: 0;
225
+ width: 100%;
226
+ height: 100%;
227
+ object-fit: cover;
228
+ /* Mirror — direction-independent (RTL-safe). */
229
+ transform: scaleX(-1);
230
+ }
231
+ .sekyro-stage__still {
232
+ position: absolute;
233
+ inset: 0;
234
+ width: 100%;
235
+ height: 100%;
236
+ object-fit: cover;
237
+ }
238
+ .sekyro-stage__arc {
239
+ pointer-events: none;
240
+ position: absolute;
241
+ inset: 0;
242
+ width: 100%;
243
+ height: 100%;
244
+ overflow: visible;
245
+ }
246
+ .sekyro-stage__corner-start {
247
+ position: absolute;
248
+ inset-block-start: 0.75rem;
249
+ inset-inline-start: 0.75rem;
250
+ }
251
+ .sekyro-stage__corner-end {
252
+ position: absolute;
253
+ inset-block-start: 0.75rem;
254
+ inset-inline-end: 0.75rem;
255
+ }
256
+ .sekyro-stage__pill {
257
+ display: inline-flex;
258
+ align-items: center;
259
+ gap: 0.5rem;
260
+ padding-block: 0.25rem;
261
+ padding-inline: 0.5rem;
262
+ border-radius: calc(var(--sekyro-radius) / 2);
263
+ background: color-mix(in srgb, var(--sekyro-color-fg) 80%, transparent);
264
+ font-size: 0.875rem;
265
+ line-height: 1.4;
266
+ color: var(--sekyro-color-surface);
267
+ }
268
+ .sekyro-stage__guidance {
269
+ position: absolute;
270
+ inset-inline: 0;
271
+ inset-block-end: 0;
272
+ margin: 0;
273
+ min-height: 2.5rem;
274
+ padding-block: 0.5rem;
275
+ padding-inline: 0.75rem;
276
+ background: color-mix(in srgb, var(--sekyro-color-fg) 80%, transparent);
277
+ text-align: center;
278
+ color: var(--sekyro-color-surface);
279
+ }
280
+ .sekyro-stage__guidance-text {
281
+ display: block;
282
+ font-size: 1rem;
283
+ line-height: 1.5;
284
+ }
285
+ .sekyro-stage__guidance-hint {
286
+ display: block;
287
+ font-size: 0.875rem;
288
+ line-height: 1.4;
289
+ }
290
+
291
+ /* Liveness v7 §4.4: while the screen-ramp wash lights the screen (screen-ramp-layer.tsx marks <html>), its cover fills
292
+ * the stage over the camera from the overlay slot; the scrim steps aside and the ring rises above the cover. The
293
+ * guidance band and the corners come after the slot, so they stay above it. */
294
+ :root[data-sekyro-ramp] .sekyro-arc__scrim {
295
+ visibility: hidden;
296
+ }
297
+ :root[data-sekyro-ramp] .sekyro-stage__arc {
298
+ z-index: 1;
299
+ }
300
+
301
+ /* ── arc (SVG) ─────────────────────────────────────────────────────────── */
302
+ .sekyro-arc__scrim {
303
+ transition: fill 300ms;
304
+ }
305
+ .sekyro-arc__ring {
306
+ transition: opacity 300ms;
307
+ }
308
+ .sekyro-arc__ring--dim {
309
+ opacity: 0.25;
310
+ }
311
+ .sekyro-arc__tick {
312
+ transition: stroke 200ms;
313
+ }
314
+ .sekyro-arc__guide {
315
+ transition: stroke 200ms;
316
+ }
317
+ .sekyro-arc__guide--spin {
318
+ stroke-dasharray: 12 10;
319
+ }
320
+
321
+ /* ── motion (ported from identity-hosted/app/globals.css:37-125) ───────── */
322
+ /* Scene fade-in: guide + scrim settle in on stage mount. */
323
+ .sekyro-capture-fade-in {
324
+ animation: sekyro-capture-fade-in 300ms var(--sekyro-ease-out, ease-out) both;
325
+ }
326
+ /* Guidance-line text swap. */
327
+ .sekyro-capture-text-in {
328
+ animation: sekyro-capture-fade-in 150ms var(--sekyro-ease-out, ease-out) both;
329
+ }
330
+ /* Camera-off trust pill fade. */
331
+ .sekyro-capture-pill-in {
332
+ animation: sekyro-capture-fade-in 200ms var(--sekyro-ease-out, ease-out) both;
333
+ }
334
+ /* Inward breathe while seeking — never expands past the gate. Origin MUST
335
+ * match the guide center or the circle orbits. */
336
+ .sekyro-capture-breathe {
337
+ animation: sekyro-capture-breathe 2.8s ease-in-out infinite;
338
+ transform-origin: 150px 150px;
339
+ }
340
+ /* One-shot lock settle on entering `locked`. */
341
+ .sekyro-capture-settle {
342
+ animation: sekyro-capture-settle 250ms var(--sekyro-ease-settle, ease-out);
343
+ transform-origin: 150px 150px;
344
+ }
345
+ /* Checking/recording spinner: the dashes CRAWL around the guide via
346
+ * stroke-dashoffset — NOT a CSS transform rotation: iOS Safari does not
347
+ * reliably animate transforms on SVG child elements. −616 = 28 × the 22px dash
348
+ * period per 2s cycle → seamless loop, one apparent lap ≈ 2s. */
349
+ .sekyro-capture-ring-spin {
350
+ animation: sekyro-capture-ring-dash 2s linear infinite;
351
+ }
352
+ /* "Photo develops" — the captured still fades + settles in. */
353
+ .sekyro-capture-develop {
354
+ animation: sekyro-capture-develop 400ms var(--sekyro-ease-out, ease-out) both;
355
+ }
356
+ /* Forced reduction (host hint, e.g. a LOW device profile): the reduced-motion
357
+ * variants even without prefers-reduced-motion. */
358
+ .sekyro-capture-reduce .sekyro-capture-fade-in,
359
+ .sekyro-capture-reduce .sekyro-capture-text-in,
360
+ .sekyro-capture-reduce .sekyro-capture-pill-in,
361
+ .sekyro-capture-reduce .sekyro-capture-breathe,
362
+ .sekyro-capture-reduce .sekyro-capture-settle,
363
+ .sekyro-capture-reduce .sekyro-capture-develop,
364
+ .sekyro-capture-reduce .sekyro-capture-ring-spin {
365
+ animation: none;
366
+ }
367
+ .sekyro-capture-reduce .sekyro-arc__guide--spin {
368
+ stroke-dasharray: none;
369
+ }
370
+
371
+ @media (prefers-reduced-motion: reduce) {
372
+ .sekyro-capture-fade-in,
373
+ .sekyro-capture-text-in,
374
+ .sekyro-capture-pill-in,
375
+ .sekyro-capture-breathe,
376
+ .sekyro-capture-settle,
377
+ .sekyro-capture-develop,
378
+ .sekyro-capture-ring-spin {
379
+ animation: none;
380
+ }
381
+ .sekyro-arc__scrim,
382
+ .sekyro-arc__ring,
383
+ .sekyro-arc__tick,
384
+ .sekyro-arc__guide {
385
+ transition: none;
386
+ }
387
+ /* Reduced motion → a static SOLID guide circle. */
388
+ .sekyro-arc__guide--spin {
389
+ stroke-dasharray: none;
390
+ }
391
+ }
392
+
393
+ @keyframes sekyro-capture-fade-in {
394
+ from {
395
+ opacity: 0;
396
+ }
397
+ }
398
+ @keyframes sekyro-capture-breathe {
399
+ 50% {
400
+ transform: scale(0.985);
401
+ opacity: 0.85;
402
+ }
403
+ }
404
+ @keyframes sekyro-capture-settle {
405
+ 0% {
406
+ transform: scale(1.03);
407
+ }
408
+ 100% {
409
+ transform: scale(1);
410
+ }
411
+ }
412
+ @keyframes sekyro-capture-ring-dash {
413
+ to {
414
+ stroke-dashoffset: -616;
415
+ }
416
+ }
417
+ @keyframes sekyro-capture-develop {
418
+ 0% {
419
+ opacity: 0;
420
+ transform: scale(1.02);
421
+ }
422
+ 75% {
423
+ opacity: 1;
424
+ }
425
+ 100% {
426
+ opacity: 1;
427
+ transform: scale(1);
428
+ }
429
+ }
430
+
431
+ /* ── pre-capture screen ────────────────────────────────────────────────── */
432
+ .sekyro-tips {
433
+ display: flex;
434
+ flex-direction: column;
435
+ gap: 0.5rem;
436
+ padding: 0.875rem;
437
+ border: 1px solid color-mix(in srgb, var(--sekyro-color-fg) 14%, transparent);
438
+ border-radius: var(--sekyro-radius);
439
+ background: var(--sekyro-color-surface);
440
+ }
441
+ .sekyro-tips__title {
442
+ margin: 0;
443
+ font-size: 0.9375rem;
444
+ font-weight: 700;
445
+ color: var(--sekyro-color-fg);
446
+ }
447
+ .sekyro-tips__list {
448
+ margin: 0;
449
+ padding: 0;
450
+ list-style: none;
451
+ display: flex;
452
+ flex-direction: column;
453
+ gap: 0.5rem;
454
+ }
455
+ .sekyro-tips__item {
456
+ display: flex;
457
+ align-items: flex-start;
458
+ gap: 0.625rem;
459
+ font-size: 0.9375rem;
460
+ line-height: 1.45;
461
+ color: var(--sekyro-color-fg);
462
+ }
463
+ .sekyro-tips__icon {
464
+ display: inline-flex;
465
+ flex-shrink: 0;
466
+ color: var(--sekyro-color-brand);
467
+ margin-block-start: 0.125rem;
468
+ }
469
+ .sekyro-permission {
470
+ display: flex;
471
+ align-items: flex-start;
472
+ gap: 0.625rem;
473
+ padding: 0.75rem;
474
+ border-radius: var(--sekyro-radius);
475
+ border: 1px solid color-mix(in srgb, var(--sekyro-color-fg) 14%, transparent);
476
+ font-size: 0.9375rem;
477
+ line-height: 1.45;
478
+ color: var(--sekyro-color-fg);
479
+ }
480
+ .sekyro-permission__icon {
481
+ display: inline-flex;
482
+ flex-shrink: 0;
483
+ margin-block-start: 0.125rem;
484
+ color: var(--sekyro-color-fg-muted);
485
+ }
486
+ .sekyro-permission--granted .sekyro-permission__icon {
487
+ color: var(--sekyro-color-success);
488
+ }
489
+ .sekyro-permission--denied {
490
+ border-color: var(--sekyro-color-warning);
491
+ background: color-mix(in srgb, var(--sekyro-color-warning) 10%, var(--sekyro-color-surface));
492
+ }
493
+ .sekyro-permission--denied .sekyro-permission__icon {
494
+ color: var(--sekyro-color-warning);
495
+ }
496
+ /* Camera choice: native radios drawn as segments. The input covers its whole
497
+ * segment (hit area = the ≥ 48px face) but is transparent; the face is its
498
+ * next sibling, so checked/focus styles need no :has(). */
499
+ .sekyro-segmented {
500
+ margin: 0;
501
+ padding: 0;
502
+ border: 0;
503
+ min-width: 0;
504
+ }
505
+ .sekyro-segmented__legend {
506
+ padding: 0;
507
+ margin-block-end: 0.5rem;
508
+ font-size: 0.9375rem;
509
+ font-weight: 600;
510
+ color: var(--sekyro-color-fg);
511
+ }
512
+ .sekyro-segmented__options {
513
+ display: grid;
514
+ grid-template-columns: 1fr 1fr;
515
+ gap: 0.5rem;
516
+ }
517
+ .sekyro-segmented__option {
518
+ position: relative;
519
+ display: flex;
520
+ }
521
+ .sekyro-segmented__input {
522
+ position: absolute;
523
+ inset: 0;
524
+ width: 100%;
525
+ height: 100%;
526
+ margin: 0;
527
+ opacity: 0;
528
+ cursor: pointer;
529
+ }
530
+ .sekyro-segmented__face {
531
+ display: flex;
532
+ flex: 1;
533
+ align-items: center;
534
+ justify-content: center;
535
+ gap: 0.5rem;
536
+ min-height: 48px;
537
+ padding-block: 0.5rem;
538
+ padding-inline: 0.75rem;
539
+ border: 1px solid color-mix(in srgb, var(--sekyro-color-fg) 30%, transparent);
540
+ border-radius: var(--sekyro-radius);
541
+ background: var(--sekyro-color-surface);
542
+ font-size: 1rem;
543
+ font-weight: 600;
544
+ line-height: 1.25;
545
+ text-align: center;
546
+ color: var(--sekyro-color-fg);
547
+ pointer-events: none;
548
+ }
549
+ /* Radio dot: hollow ring → filled ring when checked (shape, not only color). */
550
+ .sekyro-segmented__dot {
551
+ flex-shrink: 0;
552
+ width: 1rem;
553
+ height: 1rem;
554
+ border-radius: 9999px;
555
+ border: 2px solid color-mix(in srgb, var(--sekyro-color-fg) 55%, transparent);
556
+ }
557
+ .sekyro-segmented__input:checked + .sekyro-segmented__face {
558
+ border-color: var(--sekyro-color-brand);
559
+ box-shadow: inset 0 0 0 1px var(--sekyro-color-brand);
560
+ background: color-mix(in srgb, var(--sekyro-color-brand) 8%, var(--sekyro-color-surface));
561
+ }
562
+ .sekyro-segmented__input:checked + .sekyro-segmented__face .sekyro-segmented__dot {
563
+ border-color: var(--sekyro-color-brand);
564
+ box-shadow: inset 0 0 0 3px var(--sekyro-color-surface);
565
+ background: var(--sekyro-color-brand);
566
+ }
567
+ .sekyro-segmented__input:focus-visible + .sekyro-segmented__face {
568
+ outline: 3px solid var(--sekyro-color-ring);
569
+ outline-offset: 2px;
570
+ }
571
+ .sekyro-segmented__option:hover .sekyro-segmented__face {
572
+ border-color: var(--sekyro-color-brand);
573
+ }
574
+ /* Voice switch: label + track/thumb; the thumb moves AND shows a check when on. */
575
+ .sekyro-switch {
576
+ display: flex;
577
+ align-items: center;
578
+ justify-content: space-between;
579
+ gap: 0.75rem;
580
+ width: 100%;
581
+ min-height: 48px;
582
+ padding-block: 0.25rem;
583
+ padding-inline: 0.25rem;
584
+ border: 0;
585
+ border-radius: var(--sekyro-radius);
586
+ background: transparent;
587
+ font: inherit;
588
+ font-size: 1rem;
589
+ line-height: 1.4;
590
+ color: var(--sekyro-color-fg);
591
+ cursor: pointer;
592
+ text-align: start;
593
+ -webkit-tap-highlight-color: transparent;
594
+ }
595
+ .sekyro-switch:focus-visible {
596
+ outline: 3px solid var(--sekyro-color-ring);
597
+ outline-offset: 2px;
598
+ }
599
+ .sekyro-switch__label {
600
+ display: inline-flex;
601
+ align-items: center;
602
+ gap: 0.5rem;
603
+ font-weight: 600;
604
+ }
605
+ .sekyro-switch__track {
606
+ position: relative;
607
+ flex-shrink: 0;
608
+ width: 2.75rem;
609
+ height: 1.5rem;
610
+ border-radius: 9999px;
611
+ background: color-mix(in srgb, var(--sekyro-color-fg) 55%, var(--sekyro-color-surface));
612
+ transition: background-color 150ms;
613
+ }
614
+ .sekyro-switch[aria-checked="true"] .sekyro-switch__track {
615
+ background: var(--sekyro-color-brand);
616
+ }
617
+ .sekyro-switch__thumb {
618
+ position: absolute;
619
+ inset-block-start: 0.1875rem;
620
+ inset-inline-start: 0.1875rem;
621
+ display: flex;
622
+ align-items: center;
623
+ justify-content: center;
624
+ width: 1.125rem;
625
+ height: 1.125rem;
626
+ border-radius: 9999px;
627
+ background: var(--sekyro-color-surface);
628
+ color: var(--sekyro-color-brand);
629
+ transition: inset-inline-start 150ms;
630
+ }
631
+ .sekyro-switch[aria-checked="true"] .sekyro-switch__thumb {
632
+ inset-inline-start: 1.4375rem;
633
+ }
634
+ .sekyro-switch__check {
635
+ width: 0.75rem;
636
+ height: 0.75rem;
637
+ }
638
+ .sekyro-spinner {
639
+ flex-shrink: 0;
640
+ width: 1.25rem;
641
+ height: 1.25rem;
642
+ animation: sekyro-spin 0.9s linear infinite;
643
+ }
644
+ .sekyro-visually-hidden {
645
+ position: absolute;
646
+ width: 1px;
647
+ height: 1px;
648
+ margin: -1px;
649
+ padding: 0;
650
+ overflow: hidden;
651
+ clip: rect(0 0 0 0);
652
+ clip-path: inset(50%);
653
+ white-space: nowrap;
654
+ border: 0;
655
+ }
656
+ @keyframes sekyro-spin {
657
+ to {
658
+ transform: rotate(360deg);
659
+ }
660
+ }
661
+ .sekyro-capture-reduce .sekyro-spinner {
662
+ animation: none;
663
+ }
664
+ .sekyro-capture-reduce .sekyro-switch__track,
665
+ .sekyro-capture-reduce .sekyro-switch__thumb {
666
+ transition: none;
667
+ }
668
+ @media (prefers-reduced-motion: reduce) {
669
+ .sekyro-spinner {
670
+ animation: none;
671
+ }
672
+ .sekyro-switch__track,
673
+ .sekyro-switch__thumb {
674
+ transition: none;
675
+ }
676
+ }
677
+ /* Windows high contrast: backgrounds are dropped → draw the switch and the
678
+ * checked segment with system colors so the state stays visible. */
679
+ @media (forced-colors: active) {
680
+ .sekyro-switch__track {
681
+ border: 1px solid CanvasText;
682
+ }
683
+ .sekyro-switch__thumb {
684
+ background: CanvasText;
685
+ }
686
+ /* Checked = a thick Highlight border (not an outline, so the focus-visible
687
+ * outline still shows on the checked option). */
688
+ .sekyro-segmented__input:checked + .sekyro-segmented__face {
689
+ border: 3px solid Highlight;
690
+ }
691
+ /* The thumb is painted CanvasText: draw the check in Canvas so it stays visible. */
692
+ .sekyro-switch__check {
693
+ color: Canvas;
694
+ }
695
+ .sekyro-segmented__input:checked + .sekyro-segmented__face .sekyro-segmented__dot {
696
+ background: Highlight;
697
+ }
698
+ }
699
+ /* GENERATED by packages/sekyro-brand/scripts/build.mjs from tokens/tokens.json — do not edit.
700
+ The flow-* type roles of the verification flow (`font: var(--sekyro-type-flow-title) var(--sekyro-font)`), the
701
+ colours of its camera stages, its component sizes and its page transition. Prepended to dist/verification.css by tsup. */
702
+ :root {
703
+ --sekyro-type-flow-hero: 600 28px/34px;
704
+ --sekyro-tracking-flow-hero: -0.015em;
705
+ --sekyro-type-flow-title: 600 24px/30px;
706
+ --sekyro-tracking-flow-title: -0.01em;
707
+ --sekyro-type-flow-camera: 600 24px/30px;
708
+ --sekyro-tracking-flow-camera: -0.01em;
709
+ --sekyro-type-flow-body: 400 17px/24px;
710
+ --sekyro-tracking-flow-body: -0.006em;
711
+ --sekyro-type-flow-action: 600 17px/22px;
712
+ --sekyro-tracking-flow-action: -0.006em;
713
+ --sekyro-type-flow-label: 500 15px/20px;
714
+ --sekyro-tracking-flow-label: 0;
715
+ --sekyro-type-flow-input: 500 22px/28px;
716
+ --sekyro-tracking-flow-input: 0;
717
+ --sekyro-type-flow-digit: 600 28px/34px;
718
+ --sekyro-tracking-flow-digit: 0;
719
+ --sekyro-type-flow-caption: 400 13px/18px;
720
+ --sekyro-tracking-flow-caption: 0;
721
+ --sekyro-color-stage: #051a2e;
722
+ --sekyro-color-stage-accent: #69dfef;
723
+ --sekyro-color-on-stage: #ffffff;
724
+ --sekyro-color-on-camera-success: #00c897;
725
+ --sekyro-color-stage-warning: #ffab00;
726
+ --sekyro-size-button-height: 52px;
727
+ --sekyro-size-control-radius: 10px;
728
+ --sekyro-size-card-radius: 16px;
729
+ --sekyro-size-field-radius: 10px;
730
+ --sekyro-size-icon-tile: 56px;
731
+ --sekyro-size-icon-tile-radius: 16px;
732
+ --sekyro-size-header-tile: 40px;
733
+ --sekyro-size-choice-tile: 40px;
734
+ --sekyro-size-tile-radius: 10px;
735
+ --sekyro-size-result-disc: 64px;
736
+ --sekyro-size-result-ring: 8px;
737
+ --sekyro-size-progress-height: 4px;
738
+ --sekyro-size-focus-ring: 2px;
739
+ --sekyro-size-focus-ring-offset: 2px;
740
+ --sekyro-size-otp-box: 60px;
741
+ --sekyro-size-choice-min-height: 76px;
742
+ --sekyro-size-step-gap: 32px;
743
+ --sekyro-size-heading-gap: 12px;
744
+ --sekyro-motion-page: 320ms;
745
+ --sekyro-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
746
+ }
747
+ /* packages/sekyro-react/src/verification.css — @sekyro/react/verification.
748
+ Logical properties only; every color through a --sekyro-* variable (check-css). The type scale (--sekyro-type-flow-*)
749
+ and the camera colours (--sekyro-color-stage*) are generated from packages/sekyro-brand into generated/brand.css,
750
+ which tsup prepends to dist/verification.css. The flow is the native SDKs' design (sekyro-mobile/ios SekyroUI, the
751
+ 2026-10-23 premium redesign): one heading per page, quiet secondary text, white fields with hairlines, one large
752
+ action in the thumb zone, a full-bleed camera under ink. */
753
+
754
+ /* ── The SDK's faces (as on the native SDKs): Inter 400/500/600, Geist 600/700 for titles of 22 px and more,
755
+ Cairo 400/600/700 for Arabic (Latin-1 included). Static subset instances of the OFL variable fonts (renamed
756
+ "Sekyro …", see fonts/*-OFL.txt), woff2, built from sekyro-mobile/ios/Sources/SekyroUI/Resources/fonts with
757
+ fontTools. Separate assets (a bundler emits them next to this stylesheet), loaded only for the text that needs them
758
+ (unicode-range) and never blocking it (swap). ─────────────────────────────────────────────────────────────── */
759
+ @font-face { font-family: "Sekyro Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("./fonts/SekyroInter-Regular.woff2") format("woff2"); unicode-range: U+0000-017F, U+02BB-02DC, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2713, U+FEFF; }
760
+ @font-face { font-family: "Sekyro Inter"; font-style: normal; font-weight: 500; font-display: swap; src: url("./fonts/SekyroInter-Medium.woff2") format("woff2"); unicode-range: U+0000-017F, U+02BB-02DC, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2713, U+FEFF; }
761
+ @font-face { font-family: "Sekyro Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("./fonts/SekyroInter-SemiBold.woff2") format("woff2"); unicode-range: U+0000-017F, U+02BB-02DC, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2713, U+FEFF; }
762
+ @font-face { font-family: "Sekyro Geist"; font-style: normal; font-weight: 600; font-display: swap; src: url("./fonts/SekyroGeist-SemiBold.woff2") format("woff2"); unicode-range: U+0000-017F, U+02BB-02DC, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2713, U+FEFF; }
763
+ @font-face { font-family: "Sekyro Geist"; font-style: normal; font-weight: 700; font-display: swap; src: url("./fonts/SekyroGeist-Bold.woff2") format("woff2"); unicode-range: U+0000-017F, U+02BB-02DC, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2713, U+FEFF; }
764
+ @font-face { font-family: "Sekyro Cairo"; font-style: normal; font-weight: 400; font-display: swap; src: url("./fonts/SekyroCairo-Regular.woff2") format("woff2"); unicode-range: U+0020-00FF, U+0600-06FF, U+2013-2026, U+FB50-FDFF, U+FE70-FEFC; }
765
+ @font-face { font-family: "Sekyro Cairo"; font-style: normal; font-weight: 600; font-display: swap; src: url("./fonts/SekyroCairo-SemiBold.woff2") format("woff2"); unicode-range: U+0020-00FF, U+0600-06FF, U+2013-2026, U+FB50-FDFF, U+FE70-FEFC; }
766
+ @font-face { font-family: "Sekyro Cairo"; font-style: normal; font-weight: 700; font-display: swap; src: url("./fonts/SekyroCairo-Bold.woff2") format("woff2"); unicode-range: U+0020-00FF, U+0600-06FF, U+2013-2026, U+FB50-FDFF, U+FE70-FEFC; }
767
+
768
+ /* ── Generic step parts (also used outside <SekyroVerification>) ─────────── */
769
+ .sekyro-field { display: flex; flex-direction: column; gap: 0.5rem; }
770
+ .sekyro-label { font-weight: 600; color: var(--sekyro-color-fg); }
771
+ .sekyro-help { color: var(--sekyro-color-fg-muted); font-size: 0.875rem; }
772
+ .sekyro-help.is-danger { color: var(--sekyro-color-danger); }
773
+ .sekyro-input {
774
+ min-block-size: 48px;
775
+ padding-block: 0.625rem;
776
+ padding-inline: 0.875rem;
777
+ border: 1px solid var(--sekyro-color-fg-muted);
778
+ border-radius: var(--sekyro-radius);
779
+ background: var(--sekyro-color-surface);
780
+ color: var(--sekyro-color-fg);
781
+ font: inherit;
782
+ font-size: 1rem;
783
+ }
784
+ .sekyro-input:focus-visible { outline: 3px solid var(--sekyro-color-ring); outline-offset: 2px; }
785
+ .sekyro-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
786
+ .sekyro-test-code { font-weight: 600; color: var(--sekyro-color-fg); letter-spacing: 0.04em; }
787
+ .sekyro-row { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
788
+ .sekyro-center { text-align: center; }
789
+ .sekyro-result { text-align: start; }
790
+
791
+ /* ── The flow's surface ────────────────────────────────────────────────── */
792
+ /* Arabic: Cairo (Latin-1 included), Inter after it for the rest of the Latin text. */
793
+ :root { --sekyro-font-arabic: "Sekyro Cairo", Cairo, "Sekyro Inter", "Noto Sans Arabic", system-ui, -apple-system, "Segoe UI", sans-serif; }
794
+ .sekyro-root {
795
+ /* Shades derived from the (possibly partner) theme on THIS element, so a partner brand recolours them too. */
796
+ --sekyro-color-brand-soft: color-mix(in srgb, var(--sekyro-color-brand) 9%, var(--sekyro-color-surface));
797
+ --sekyro-color-line: color-mix(in srgb, var(--sekyro-color-fg) 22%, var(--sekyro-color-surface));
798
+ --sekyro-color-line-strong: color-mix(in srgb, var(--sekyro-color-fg) 50%, var(--sekyro-color-surface));
799
+ --sekyro-color-line-subtle: color-mix(in srgb, var(--sekyro-color-fg) 11%, var(--sekyro-color-surface));
800
+ --sekyro-color-sunken: color-mix(in srgb, var(--sekyro-color-fg) 6%, var(--sekyro-color-surface));
801
+ --sekyro-color-fg-subtle: color-mix(in srgb, var(--sekyro-color-fg-muted) 80%, var(--sekyro-color-surface));
802
+ /* Titles of 22 px and more: Geist while the font is Sekyro's (set on the flow), else the theme's font. */
803
+ --sekyro-font-display: var(--sekyro-font);
804
+ --sekyro-gutter: 1.5rem;
805
+ --sekyro-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
806
+ --sekyro-ease: cubic-bezier(0.22, 1, 0.36, 1);
807
+ /* UX refresh 2026-11-05 (prototype): cards keep the brand's 16 px whatever the partner's control radius (a "full"
808
+ partner radius makes pill buttons, never pill cards); the tiles and the page motion on the prototype's values. */
809
+ --sekyro-radius-card: var(--sekyro-size-card-radius);
810
+ --sekyro-radius-tile: var(--sekyro-size-icon-tile-radius);
811
+ --sekyro-focus: var(--sekyro-size-focus-ring) solid var(--sekyro-color-ring);
812
+ /* The soft status roles where the flow sets none (<SekyroVerification> sets them from generated/brand-flow.ts). */
813
+ --sekyro-color-info-soft-fallback: color-mix(in srgb, var(--sekyro-color-brand) 9%, var(--sekyro-color-surface));
814
+ }
815
+ /* The flow paints its own surface, so a dark scheme reads on any host page. */
816
+ .sekyro-verification {
817
+ display: flex; flex-direction: column; background: var(--sekyro-color-surface); color-scheme: light;
818
+ /* No double-tap zoom on the flow's taps (pinch zoom stays: it is the host's and the person's). */
819
+ touch-action: manipulation;
820
+ }
821
+ .sekyro-verification--dark { color-scheme: dark; }
822
+ .sekyro-flow {
823
+ --sekyro-inline-sign: 1;
824
+ display: flex; flex-direction: column; flex: 1; gap: 0.75rem;
825
+ padding-inline: var(--sekyro-gutter);
826
+ font: var(--sekyro-type-flow-body) var(--sekyro-font);
827
+ letter-spacing: var(--sekyro-tracking-flow-body);
828
+ font-optical-sizing: auto;
829
+ }
830
+ .sekyro-flow[dir="rtl"] { --sekyro-inline-sign: -1; }
831
+ .sekyro-verification.is-immersive { background: var(--sekyro-color-stage); }
832
+ .sekyro-verification.is-immersive .sekyro-flow { gap: 0; }
833
+ /* Sizes are outer sizes (a 52px field is 52px with its padding and border), as in the native kits. */
834
+ .sekyro-root :is(.sekyro-input, .sekyro-btn, .sekyro-card, .sekyro-phone, .sekyro-otp-box, .sekyro-org__tile, .sekyro-glass) { box-sizing: border-box; }
835
+ /* Arabic: Cairo first, tracking reset (joined letters must not part), taller lines for its marks. */
836
+ .sekyro-root [lang="ar"] { font-family: var(--sekyro-font-arabic); }
837
+ .sekyro-root [lang="ar"] * { letter-spacing: 0 !important; }
838
+ /* A step title takes focus on mount so screen readers announce it; it is not a control, so it draws no ring. */
839
+ .sekyro-root [tabindex="-1"]:focus { outline: none; }
840
+
841
+ /* ── Shell: the partner bar, the thin step progress, the footer ───────── */
842
+ /* The prototype's header: a 40 px tile (logo or initials on brand-soft), the name on title-sm, the caption under it,
843
+ a line-subtle hairline across the whole flow. */
844
+ .sekyro-org {
845
+ display: flex; align-items: center; gap: 0.75rem; padding-block: 0.75rem;
846
+ margin-inline: calc(-1 * var(--sekyro-gutter)); padding-inline: var(--sekyro-gutter);
847
+ border-block-end: 1px solid var(--sekyro-color-line-subtle);
848
+ }
849
+ .sekyro-org__tile {
850
+ display: inline-grid; place-items: center; flex-shrink: 0; overflow: hidden;
851
+ inline-size: var(--sekyro-size-header-tile); block-size: var(--sekyro-size-header-tile); border-radius: var(--sekyro-size-tile-radius);
852
+ background: var(--sekyro-color-brand-soft); color: var(--sekyro-color-brand);
853
+ font: var(--sekyro-type-flow-label) var(--sekyro-font); font-weight: 700;
854
+ }
855
+ .sekyro-org__logo { inline-size: 100%; block-size: 100%; padding: 4px; object-fit: contain; box-sizing: border-box; }
856
+ .sekyro-org__text { flex: 1; min-inline-size: 0; }
857
+ /* plaintext: a Latin org name on an Arabic page is cut at its own end, not its start. */
858
+ .sekyro-org__name { margin: 0; font: var(--sekyro-type-flow-action) var(--sekyro-font); color: var(--sekyro-color-fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; unicode-bidi: plaintext; text-align: match-parent; }
859
+ /* The close: a 36 px sunken disc in a 44 px target, its disc on the gutter (mirrored in Arabic by the flex row). */
860
+ .sekyro-org__end { flex-shrink: 0; display: flex; align-items: center; }
861
+ .sekyro-org__close { flex-shrink: 0; margin-inline-end: -4px; }
862
+ /* The back disc before the tile; its chevron points to the start, so it turns round in Arabic. */
863
+ .sekyro-org__back { flex-shrink: 0; margin-inline-start: -4px; }
864
+ .sekyro-flow[dir="rtl"] .sekyro-org__back .sekyro-glyph { transform: scaleX(-1); }
865
+ /* A phone keeps room for the name: with a back disc the org tile steps aside (the name still says who asks). */
866
+ @media (max-width: 430px) { .sekyro-org__back + .sekyro-org__tile { display: none; } }
867
+ .sekyro-org__sub { margin: 0; font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: var(--sekyro-color-fg-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
868
+ .sekyro-progress { margin: 0; }
869
+ .sekyro-progress__bars { display: flex; gap: 4px; margin: 0; padding: 0; list-style: none; }
870
+ .sekyro-progress__bar { position: relative; flex: 1; block-size: var(--sekyro-size-progress-height); overflow: hidden; border-radius: 9999px; background: var(--sekyro-color-line-subtle); }
871
+ .sekyro-progress__bar::before {
872
+ content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 0;
873
+ border-radius: inherit; background: var(--sekyro-color-brand); transition: inline-size 450ms var(--sekyro-ease);
874
+ }
875
+ .sekyro-progress__bar.is-done::before { inline-size: 100%; }
876
+ /* The current step is under way, not done: the brand at 70 %. */
877
+ .sekyro-progress__bar.is-current::before { inline-size: 100%; background: color-mix(in srgb, var(--sekyro-color-brand) 70%, transparent); }
878
+ .sekyro-footer {
879
+ display: flex; align-items: center; justify-content: center; gap: 0.25rem; margin: 0; padding-block: 1rem 0.5rem;
880
+ font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: var(--sekyro-color-fg-muted);
881
+ }
882
+ .sekyro-footer .sekyro-glyph { inline-size: 0.75rem; block-size: 0.75rem; }
883
+ /* D16: the attribution is a link to sekyro.ai: the muted caption (its contrast holds), underlined on hover, the
884
+ focus ring of every control. */
885
+ a.sekyro-footer { text-decoration: none; border-radius: 0.25rem; }
886
+ a.sekyro-footer:hover { text-decoration: underline; text-underline-offset: 0.2em; }
887
+ a.sekyro-footer:focus-visible { outline: var(--sekyro-focus); outline-offset: 2px; }
888
+ .sekyro-glyph { inline-size: 1.25rem; block-size: 1.25rem; flex-shrink: 0; fill: none; }
889
+
890
+ /* ── Pages: one at a time, rising into place ───────────────────────────── */
891
+ .sekyro-page { display: flex; flex-direction: column; flex: 1; min-block-size: 0; transition: opacity 100ms ease-out; }
892
+ .sekyro-page.is-leaving { opacity: 0; pointer-events: none; }
893
+ .sekyro-page > * { animation: sekyro-rise var(--sekyro-motion-page) var(--sekyro-ease-out) 40ms both; }
894
+ @keyframes sekyro-rise { from { opacity: 0; transform: translateY(10px); } }
895
+ .sekyro-step { display: flex; flex-direction: column; flex: 1; gap: var(--sekyro-size-step-gap); padding-block-start: 1.5rem; }
896
+ .sekyro-heading { display: flex; flex-direction: column; gap: var(--sekyro-size-heading-gap); }
897
+ .sekyro-root .sekyro-heading > h2,
898
+ .sekyro-root .sekyro-heading > h1 {
899
+ margin: 0; font: var(--sekyro-type-flow-title) var(--sekyro-font-display); letter-spacing: var(--sekyro-tracking-flow-title);
900
+ color: var(--sekyro-color-fg); text-wrap: balance;
901
+ }
902
+ .sekyro-root .sekyro-heading > p { margin: 0; font: var(--sekyro-type-flow-body) var(--sekyro-font); letter-spacing: var(--sekyro-tracking-flow-body); color: var(--sekyro-color-fg-muted); }
903
+ .sekyro-root [lang="ar"] .sekyro-heading > :is(h1, h2) { font-family: var(--sekyro-font-arabic); line-height: 1.4; }
904
+ .sekyro-root [lang="ar"] .sekyro-heading > p { font-family: var(--sekyro-font-arabic); line-height: 1.6; }
905
+ /* Other titles in the flow (processing, unsupported, the 0.1 method screen) on the same scale. */
906
+ .sekyro-root :is(h1, h2).sekyro-text-body { font: var(--sekyro-type-flow-title) var(--sekyro-font-display); letter-spacing: var(--sekyro-tracking-flow-title); }
907
+ .sekyro-root [lang="ar"] :is(h1, h2).sekyro-text-body { font-family: var(--sekyro-font-arabic); line-height: 1.4; }
908
+
909
+ /* The page's actions, pinned in the thumb zone; the consent line under them (decision 1). */
910
+ .sekyro-actions {
911
+ position: sticky; inset-block-end: 0; z-index: 1;
912
+ display: flex; flex-direction: column; gap: 0.75rem; margin-block-start: auto; padding-block: 0.75rem 0.25rem;
913
+ background: var(--sekyro-color-surface);
914
+ }
915
+ /* The consent line: a caption, centred under the actions (or after a page without any). */
916
+ .sekyro-consent { margin: 0; padding-block: 0.25rem; }
917
+ .sekyro-consent__line { margin: 0; text-align: center; font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: var(--sekyro-color-fg-muted); text-wrap: balance; }
918
+ .sekyro-root .sekyro-link.sekyro-link--inline { align-self: auto; min-block-size: 0; padding-block: 0.375rem; font: inherit; color: var(--sekyro-color-brand); text-decoration: underline; text-underline-offset: 0.2em; }
919
+ .sekyro-actions:empty { display: none; }
920
+ .sekyro-actions__group { display: flex; flex-direction: column; gap: 0.75rem; }
921
+ .sekyro-actions__group > .sekyro-label { font: var(--sekyro-type-flow-label) var(--sekyro-font); color: var(--sekyro-color-fg-muted); margin: 0; }
922
+
923
+ /* Buttons (prototype): 52 px, the partner's control radius (10 px by default), the flow's action type. Primary is the
924
+ brand fill; secondary is outlined; ghost is a quiet brand text action; danger fills with the danger role. A disabled
925
+ primary is the brand at 40 %. */
926
+ .sekyro-root .sekyro-btn {
927
+ min-block-size: var(--sekyro-size-button-height); gap: 0.5rem; padding-inline: 1.5rem; border-radius: var(--sekyro-radius);
928
+ font: var(--sekyro-type-flow-action) var(--sekyro-font); letter-spacing: var(--sekyro-tracking-flow-action);
929
+ transition: background-color 150ms, border-color 150ms, transform 250ms var(--sekyro-spring);
930
+ }
931
+ .sekyro-root .sekyro-btn:focus-visible { outline: var(--sekyro-focus); outline-offset: 2px; }
932
+ .sekyro-root .sekyro-btn:active:not(:disabled):not([aria-disabled="true"]) { transform: scale(0.97); }
933
+ .sekyro-root .sekyro-btn--primary:disabled {
934
+ opacity: 1;
935
+ background: color-mix(in srgb, var(--sekyro-color-brand) 40%, var(--sekyro-color-surface));
936
+ color: var(--sekyro-color-brand-fg);
937
+ }
938
+ .sekyro-root .sekyro-btn--secondary { border-color: var(--sekyro-color-line); background: var(--sekyro-color-surface); color: var(--sekyro-color-fg); }
939
+ .sekyro-root .sekyro-btn--secondary:hover { background: var(--sekyro-color-sunken); }
940
+ .sekyro-root .sekyro-btn--secondary:disabled { opacity: 1; color: var(--sekyro-color-fg-subtle); }
941
+ .sekyro-root .sekyro-btn--ghost { border-color: transparent; background: transparent; color: var(--sekyro-color-brand); }
942
+ .sekyro-root .sekyro-btn--ghost:hover { background: var(--sekyro-color-brand-soft); }
943
+ .sekyro-root .sekyro-btn--ghost:disabled { opacity: 1; color: var(--sekyro-color-fg-subtle); }
944
+ .sekyro-root .sekyro-btn--danger { border-color: transparent; background: var(--sekyro-color-danger); color: var(--sekyro-color-on-danger, var(--sekyro-color-surface)); }
945
+ .sekyro-root .sekyro-btn--danger:hover { background: color-mix(in srgb, var(--sekyro-color-danger) 90%, var(--sekyro-color-fg)); }
946
+ .sekyro-root .sekyro-btn[aria-busy="true"]::after {
947
+ content: ""; inline-size: 1rem; block-size: 1rem; border-radius: 50%;
948
+ border: 2px solid currentColor; border-inline-end-color: transparent; animation: sekyro-turn 0.9s linear infinite;
949
+ }
950
+ @keyframes sekyro-turn { to { transform: rotate(360deg); } }
951
+ /* A quiet text action (resend, change number, change document): the brand on the label type, a 44 px target. */
952
+ .sekyro-link {
953
+ align-self: flex-start; min-block-size: 44px; padding: 0; border: 0; background: none; cursor: pointer;
954
+ font: var(--sekyro-type-flow-label) var(--sekyro-font); color: var(--sekyro-color-brand);
955
+ }
956
+ .sekyro-link:disabled { cursor: default; color: var(--sekyro-color-fg-muted); }
957
+ .sekyro-links { display: flex; flex-wrap: wrap; column-gap: 1.5rem; }
958
+ .sekyro-otp-expiry { margin-block-start: 4px; }
959
+ .sekyro-resend { align-self: center; padding-inline: 0.5rem; font: var(--sekyro-type-flow-label) var(--sekyro-font); }
960
+ .sekyro-resend:disabled { color: var(--sekyro-color-fg-muted); cursor: default; }
961
+ p.sekyro-resend { display: flex; align-items: center; min-block-size: 44px; margin: 0; color: var(--sekyro-color-fg-muted); font-variant-numeric: tabular-nums; }
962
+ .sekyro-resend-row { display: flex; flex-wrap: wrap; justify-content: center; column-gap: 1.5rem; }
963
+ .sekyro-resend-row > .sekyro-resend { align-self: center; }
964
+ .sekyro-link:focus-visible, .sekyro-card:focus-visible, .sekyro-row-btn:focus-visible, .sekyro-reference:focus-visible { outline: var(--sekyro-focus); outline-offset: 2px; }
965
+
966
+ /* Notices (as on the native SDKs): a soft tint, the tone's -fg text, the tone's icon at the start; no border. On a
967
+ partner page the soft surfaces come from the chosen standard status set (set by the flow). */
968
+ .sekyro-root .sekyro-notice {
969
+ border-color: transparent; border-radius: var(--sekyro-radius-card); padding: 0.875rem 1rem;
970
+ font: var(--sekyro-type-flow-label) var(--sekyro-font);
971
+ }
972
+ .sekyro-root .sekyro-notice:has(> .sekyro-notice__icon) { flex-direction: row; align-items: flex-start; gap: 0.75rem; }
973
+ .sekyro-notice__icon { display: inline-grid; flex-shrink: 0; padding-block-start: 1px; }
974
+ .sekyro-notice__body { display: flex; flex-direction: column; gap: 0.5rem; flex: 1; min-inline-size: 0; }
975
+ .sekyro-root .sekyro-notice--info { background: var(--sekyro-color-info-soft, var(--sekyro-color-info-soft-fallback)); color: var(--sekyro-color-info-fg, var(--sekyro-color-fg)); }
976
+ .sekyro-root .sekyro-notice--warning { background: var(--sekyro-color-warning-soft, color-mix(in srgb, var(--sekyro-color-warning) 10%, var(--sekyro-color-surface))); color: var(--sekyro-color-warning-fg, var(--sekyro-color-fg)); }
977
+ .sekyro-root .sekyro-notice--danger { background: var(--sekyro-color-danger-soft, color-mix(in srgb, var(--sekyro-color-danger) 8%, var(--sekyro-color-surface))); color: var(--sekyro-color-danger-fg, var(--sekyro-color-fg)); }
978
+ .sekyro-root .sekyro-notice .sekyro-btn { align-self: flex-start; min-block-size: 44px; }
979
+
980
+ /* ── Fields: white with a hairline; a 2px ring on focus (red with an error) ── */
981
+ .sekyro-root .sekyro-label { font: var(--sekyro-type-flow-label) var(--sekyro-font); color: var(--sekyro-color-fg-muted); }
982
+ .sekyro-root .sekyro-help { font: var(--sekyro-type-flow-caption) var(--sekyro-font); }
983
+ .sekyro-root .sekyro-help.is-danger { color: var(--sekyro-color-danger); }
984
+ .sekyro-root .sekyro-input {
985
+ min-block-size: 52px; padding-inline: 1rem;
986
+ border-color: var(--sekyro-color-line); border-radius: var(--sekyro-radius); background: var(--sekyro-color-surface);
987
+ /* The input role (17 px): iOS Safari zooms into any focused field under 16 px (the body role is 15 px). */
988
+ font: var(--sekyro-type-flow-input) var(--sekyro-font);
989
+ transition: border-color 150ms, box-shadow 150ms;
990
+ }
991
+ .sekyro-root .sekyro-input::placeholder, .sekyro-phone__input::placeholder { color: var(--sekyro-color-fg-subtle); }
992
+ .sekyro-root .sekyro-input:focus-visible,
993
+ .sekyro-phone:focus-within {
994
+ outline: none; border-color: var(--sekyro-color-ring); box-shadow: inset 0 0 0 1px var(--sekyro-color-ring);
995
+ }
996
+ .sekyro-root .sekyro-input[aria-invalid="true"] { border-color: var(--sekyro-color-danger); box-shadow: inset 0 0 0 1px var(--sekyro-color-danger); }
997
+ .sekyro-root .sekyro-input--number { font: var(--sekyro-type-flow-input) var(--sekyro-font-display); font-variant-numeric: tabular-nums; direction: ltr; }
998
+ /* The phone: 🇲🇷 +222 as a fixed segment, then the national number large and tabular. */
999
+ .sekyro-phone {
1000
+ display: flex; align-items: center; gap: 0.75rem; min-block-size: 60px; padding-inline: 1rem;
1001
+ border: 1px solid var(--sekyro-color-line); border-radius: var(--sekyro-radius); background: var(--sekyro-color-surface);
1002
+ font: var(--sekyro-type-flow-input) var(--sekyro-font-display); font-variant-numeric: tabular-nums;
1003
+ transition: border-color 150ms, box-shadow 150ms; cursor: text;
1004
+ }
1005
+ .sekyro-phone:has([aria-invalid="true"]) { border-color: var(--sekyro-color-danger); box-shadow: inset 0 0 0 1px var(--sekyro-color-danger); }
1006
+ .sekyro-phone__lead { position: relative; display: flex; flex: none; align-items: center; align-self: stretch; margin-inline-start: -1rem; padding-inline-start: 1rem; }
1007
+ .sekyro-phone__dial { display: inline-flex; align-items: center; gap: 6px; padding-inline-end: 0.75rem; border-inline-end: 1px solid var(--sekyro-color-line); color: var(--sekyro-color-fg); }
1008
+ .sekyro-phone__flag { font-size: 1.25rem; line-height: 1; }
1009
+ /* Several contact countries (person data spec Q16): a native select, transparent, over the whole segment from the field's edge. 17 px text keeps iOS from zooming on focus. */
1010
+ .sekyro-phone__country {
1011
+ position: absolute; inset: 0; z-index: 1; inline-size: 100%; block-size: 100%; margin: 0; padding: 0;
1012
+ border: 0; opacity: 0; appearance: none; cursor: pointer;
1013
+ font: var(--sekyro-type-flow-input) var(--sekyro-font);
1014
+ }
1015
+ /* The chevron is drawn here so the JS bundle carries no extra icon; the tighter segment keeps nine digits in view at 320 px. */
1016
+ .sekyro-phone:has(.sekyro-phone__country) { padding-inline-end: 0.5rem; }
1017
+ /* Nine grouped digits stay in view beside the chevron on the narrowest phones (phone rules spec 2026-11-02 §4.1). */
1018
+ @media (max-width: 359px) { .sekyro-phone:has(.sekyro-phone__country) { gap: 0.5rem; padding-inline-end: 0.25rem; } }
1019
+ .sekyro-phone__country + .sekyro-phone__dial { gap: 4px; padding-inline-end: 0.5rem; }
1020
+ .sekyro-phone__country + .sekyro-phone__dial::after {
1021
+ content: ""; inline-size: 7px; block-size: 7px; margin-block-start: -4px; margin-inline-start: 2px;
1022
+ border-block-end: 1.5px solid var(--sekyro-color-fg-muted); border-inline-end: 1.5px solid var(--sekyro-color-fg-muted);
1023
+ transform: rotate(45deg);
1024
+ }
1025
+ .sekyro-phone__country:focus-visible + .sekyro-phone__dial { border-radius: 4px; outline: 2px solid var(--sekyro-color-ring); outline-offset: 2px; }
1026
+ .sekyro-phone__input {
1027
+ flex: 1; min-inline-size: 0; padding: 0; border: 0; outline: none; background: transparent;
1028
+ font: inherit; font-variant-numeric: tabular-nums; color: var(--sekyro-color-fg); caret-color: var(--sekyro-color-brand);
1029
+ }
1030
+
1031
+ /* The one-time code: full-width boxes over ONE input (paste and autofill land in it). */
1032
+ .sekyro-otp-boxes { position: relative; }
1033
+ .sekyro-otp-row { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 0.5rem; }
1034
+ .sekyro-otp-row.is-shaking { animation: sekyro-shake 400ms linear; }
1035
+ @keyframes sekyro-shake {
1036
+ 20% { transform: translateX(calc(8px * var(--sekyro-inline-sign))); }
1037
+ 40% { transform: translateX(calc(-8px * var(--sekyro-inline-sign))); }
1038
+ 60% { transform: translateX(calc(6px * var(--sekyro-inline-sign))); }
1039
+ 80% { transform: translateX(calc(-4px * var(--sekyro-inline-sign))); }
1040
+ }
1041
+ .sekyro-otp-box {
1042
+ position: relative; display: grid; place-items: center; block-size: var(--sekyro-size-otp-box);
1043
+ /* The control radius, capped: a partner's pill radius would turn the boxes into circles. */
1044
+ border: 1px solid var(--sekyro-color-line); border-radius: min(var(--sekyro-radius), var(--sekyro-size-card-radius)); background: var(--sekyro-color-surface);
1045
+ font: var(--sekyro-type-flow-digit) var(--sekyro-font-display); font-variant-numeric: tabular-nums; color: var(--sekyro-color-fg);
1046
+ transition: border-color 150ms, box-shadow 150ms;
1047
+ }
1048
+ .sekyro-otp-box.is-filled { border-color: var(--sekyro-color-line-strong); }
1049
+ .sekyro-otp-box.is-current { border-color: var(--sekyro-color-ring); box-shadow: inset 0 0 0 1px var(--sekyro-color-ring); }
1050
+ .sekyro-otp-box.is-current:empty::after {
1051
+ content: ""; inline-size: 2px; block-size: 26px; background: var(--sekyro-color-brand); animation: sekyro-caret 1.06s steps(1) infinite;
1052
+ }
1053
+ @keyframes sekyro-caret { 50% { opacity: 0; } }
1054
+ .sekyro-otp-box.is-invalid { border-color: var(--sekyro-color-danger); box-shadow: inset 0 0 0 1px var(--sekyro-color-danger); }
1055
+ .sekyro-otp-digit { animation: sekyro-pop 280ms var(--sekyro-spring) both; }
1056
+ @keyframes sekyro-pop { from { opacity: 0; transform: scale(0.6); } }
1057
+ .sekyro-otp-boxes .sekyro-input--code {
1058
+ position: absolute; inset: 0; inline-size: 100%; block-size: 100%; min-block-size: 0;
1059
+ padding: 0; border: 0; background: transparent; color: transparent; caret-color: transparent; letter-spacing: 0;
1060
+ /* Invisible, but 16px: iOS Safari zooms the page into any focused field whose text is smaller. */
1061
+ font-size: 16px;
1062
+ }
1063
+ .sekyro-otp-boxes .sekyro-input--code:focus-visible { outline: none; box-shadow: none; }
1064
+
1065
+ /* ── Choices: quiet cards with a radio that fills once chosen; tap rows ── */
1066
+ .sekyro-choices { display: flex; flex-direction: column; gap: 0.75rem; }
1067
+ /* Choice cards (prototype): a 40 px icon tile (line-subtle, brand-soft once chosen), the label and caption, the radio;
1068
+ the card radius is the brand's 16 px (never the partner's control radius); chosen = a brand border. */
1069
+ .sekyro-card {
1070
+ display: flex; align-items: center; gap: 0.875rem; inline-size: 100%; min-block-size: var(--sekyro-size-choice-min-height); padding-block: 0.75rem; padding-inline: 1rem;
1071
+ border: 1px solid var(--sekyro-color-line); border-radius: var(--sekyro-radius-card); background: var(--sekyro-color-surface);
1072
+ color: var(--sekyro-color-fg); font: inherit; text-align: start; cursor: pointer;
1073
+ transition: border-color 150ms, background-color 150ms, box-shadow 150ms, transform 250ms var(--sekyro-spring);
1074
+ }
1075
+ .sekyro-card:active { transform: scale(0.98); }
1076
+ .sekyro-card:disabled { cursor: default; }
1077
+ .sekyro-card__tile {
1078
+ display: inline-grid; place-items: center; flex-shrink: 0; inline-size: var(--sekyro-size-choice-tile); block-size: var(--sekyro-size-choice-tile);
1079
+ border-radius: var(--sekyro-size-tile-radius); background: var(--sekyro-color-line-subtle); color: var(--sekyro-color-fg-muted); transition: background-color 150ms, color 150ms;
1080
+ }
1081
+ .sekyro-card__tile > .sekyro-glyph { inline-size: 22px; block-size: 22px; }
1082
+ .sekyro-card:hover:not(:disabled) { border-color: var(--sekyro-color-line-strong); }
1083
+ .sekyro-card__body { display: flex; flex-direction: column; gap: 2px; flex: 1; }
1084
+ .sekyro-card__title { font: var(--sekyro-type-flow-action) var(--sekyro-font); }
1085
+ .sekyro-card__sub { font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: var(--sekyro-color-fg-muted); }
1086
+ .sekyro-radio { position: relative; flex-shrink: 0; inline-size: 22px; block-size: 22px; border-radius: 50%; border: 1.5px solid var(--sekyro-color-fg-subtle); box-sizing: border-box; }
1087
+ .sekyro-radio::after { content: ""; position: absolute; inset: 4px; border-radius: 50%; background: var(--sekyro-color-brand); transform: scale(0.2); opacity: 0; transition: transform 300ms var(--sekyro-spring), opacity 150ms; }
1088
+ .sekyro-card[aria-pressed="true"] { border-color: var(--sekyro-color-line-brand, var(--sekyro-color-brand)); box-shadow: inset 0 0 0 1px var(--sekyro-color-line-brand, var(--sekyro-color-brand)); }
1089
+ .sekyro-card[aria-pressed="true"] .sekyro-card__tile { background: var(--sekyro-color-brand-soft); color: var(--sekyro-color-brand); }
1090
+ .sekyro-card[aria-pressed="true"] .sekyro-radio { border-color: var(--sekyro-color-brand); }
1091
+ .sekyro-card[aria-pressed="true"] .sekyro-radio::after { transform: scale(1); opacity: 1; }
1092
+ @media (prefers-reduced-motion: reduce) { .sekyro-card, .sekyro-radio::after { transition: none; } }
1093
+ .sekyro-rows { margin: 0; padding: 0; list-style: none; border: 1px solid var(--sekyro-color-line-subtle); border-radius: var(--sekyro-radius-card); overflow: hidden; }
1094
+ .sekyro-rows > li + li { border-block-start: 1px solid var(--sekyro-color-line-subtle); }
1095
+ .sekyro-row-btn {
1096
+ display: flex; align-items: center; gap: 0.75rem; inline-size: 100%; min-block-size: 52px; padding-inline: 1rem;
1097
+ border: 0; background: var(--sekyro-color-surface); color: var(--sekyro-color-fg); font: inherit; text-align: start; cursor: pointer;
1098
+ }
1099
+ .sekyro-row-btn:active { background: var(--sekyro-color-sunken); }
1100
+ .sekyro-row-btn::after {
1101
+ content: ""; margin-inline-start: auto; inline-size: 7px; block-size: 7px;
1102
+ border-block-start: 1.5px solid var(--sekyro-color-fg-subtle); border-inline-end: 1.5px solid var(--sekyro-color-fg-subtle);
1103
+ transform: rotate(calc(45deg * var(--sekyro-inline-sign)));
1104
+ }
1105
+ .sekyro-row-btn__flag { font-size: 1.375rem; line-height: 1; }
1106
+
1107
+ /* A small label over a group (the ICAO tips' "For your ID photo:"). */
1108
+ .sekyro-section-label { margin: 0; font: var(--sekyro-type-flow-label) var(--sekyro-font); color: var(--sekyro-color-fg-muted); }
1109
+
1110
+ /* Tips: a line icon, then the words, unboxed. */
1111
+ .sekyro-tiprows { display: flex; flex-direction: column; gap: 1.25rem; margin: 0; padding: 0; list-style: none; }
1112
+ .sekyro-tiprows > li { display: flex; align-items: center; gap: 1rem; }
1113
+ .sekyro-tiprows .sekyro-glyph { inline-size: 22px; block-size: 22px; color: var(--sekyro-color-fg-muted); }
1114
+
1115
+ .sekyro-disc {
1116
+ display: inline-grid; place-items: center; inline-size: 44px; block-size: 44px; padding: 4px; border: 0; border-radius: 50%;
1117
+ background: var(--sekyro-color-sunken); background-clip: content-box; color: var(--sekyro-color-fg); cursor: pointer;
1118
+ }
1119
+ .sekyro-disc .sekyro-glyph { inline-size: 18px; block-size: 18px; }
1120
+
1121
+ /* ── The camera intros' marks: line geometry of what the camera will do ── */
1122
+ .sekyro-mark { display: block; margin-inline: auto; overflow: visible; }
1123
+ .sekyro-mark--card { inline-size: min(100%, 15.75rem); margin-block: 0.75rem; }
1124
+ .sekyro-mark--face { inline-size: 10.5rem; }
1125
+ .sekyro-mark__card { fill: var(--sekyro-color-surface); stroke: var(--sekyro-color-line); stroke-width: 1; }
1126
+ .sekyro-mark__photo { fill: var(--sekyro-color-sunken); }
1127
+ .sekyro-mark__text { fill: var(--sekyro-color-line-subtle); }
1128
+ .sekyro-mark__brackets { fill: none; stroke: var(--sekyro-color-brand); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
1129
+ .sekyro-mark__beam { fill: var(--sekyro-color-stage-accent); filter: drop-shadow(0 0 3px var(--sekyro-color-stage-accent)); }
1130
+ /* The card does not mirror in Arabic (a physical card reads left to right): the line crosses it left to right. */
1131
+ .sekyro-mark__read { animation: sekyro-mark-read 1.6s cubic-bezier(0.16, 1, 0.3, 1) 0.5s infinite; }
1132
+ @keyframes sekyro-mark-read { from { transform: translate(0, 0); } 70%, to { transform: translate(var(--sekyro-read-w), 0); } }
1133
+ .sekyro-mark__line { stroke: var(--sekyro-color-line); stroke-width: 1; }
1134
+ .sekyro-mark__face { fill: none; stroke: var(--sekyro-color-brand); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
1135
+ .sekyro-mark__ticks { fill: none; stroke: var(--sekyro-color-line); stroke-width: 10; stroke-dasharray: 0.26 0.74; }
1136
+ .sekyro-mark__ticks--light { stroke: var(--sekyro-color-stage-accent); }
1137
+ .sekyro-mark__arc { stroke-dasharray: 0.22 0.78; animation: sekyro-arc 2.4s linear infinite; }
1138
+ @keyframes sekyro-arc { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
1139
+
1140
+ /* ── The outcome (prototype): the approved disc in its ring, or a soft status tile; title-lg; the reference ── */
1141
+ .sekyro-root .sekyro-result { display: flex; flex-direction: column; flex: 1; padding-block-start: 2rem; }
1142
+ .sekyro-result__body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.25rem; flex: 1; padding-block-end: 2rem; text-align: center; }
1143
+ .sekyro-root .sekyro-result .sekyro-heading { align-items: center; }
1144
+ /* The approved disc (64 px) in its soft ring (8 px each side). */
1145
+ .sekyro-outcome { inline-size: calc(var(--sekyro-size-result-disc) + 2 * var(--sekyro-size-result-ring)); block-size: calc(var(--sekyro-size-result-disc) + 2 * var(--sekyro-size-result-ring)); }
1146
+ .sekyro-outcome__ring { fill: var(--sekyro-color-success-soft, color-mix(in srgb, var(--sekyro-color-success) 14%, var(--sekyro-color-surface))); transform-origin: center; transform-box: fill-box; animation: sekyro-fill 380ms var(--sekyro-spring) both; }
1147
+ .sekyro-outcome__disc { fill: var(--sekyro-color-success); transform-origin: center; transform-box: fill-box; animation: sekyro-fill 380ms var(--sekyro-spring) 120ms both; }
1148
+ @keyframes sekyro-fill { from { opacity: 0; transform: scale(0.86); } }
1149
+ .sekyro-outcome__glyph {
1150
+ fill: none; stroke: var(--sekyro-color-on-success, var(--sekyro-color-surface)); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
1151
+ stroke-dasharray: 1; stroke-dashoffset: 1; animation: sekyro-draw 320ms ease-out 380ms forwards;
1152
+ }
1153
+ @keyframes sekyro-draw { to { stroke-dashoffset: 0; } }
1154
+ .sekyro-outcome-tile { animation: sekyro-fill 380ms var(--sekyro-spring) both; }
1155
+
1156
+ /* ── The status block (prototype): a soft 56 px tile and its Solar icon, the title, the lines; centred ───── */
1157
+ .sekyro-tile {
1158
+ position: relative; display: inline-grid; place-items: center; flex-shrink: 0;
1159
+ inline-size: var(--sekyro-size-icon-tile); block-size: var(--sekyro-size-icon-tile); border-radius: var(--sekyro-radius-tile);
1160
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sekyro-color-fg) 5%, transparent);
1161
+ }
1162
+ .sekyro-tile > .sekyro-glyph { inline-size: 32px; block-size: 32px; }
1163
+ .sekyro-tile--neutral { background: var(--sekyro-color-line-subtle); color: var(--sekyro-color-fg-muted); }
1164
+ .sekyro-tile--brand { background: var(--sekyro-color-brand-soft); color: var(--sekyro-color-brand); }
1165
+ .sekyro-tile--info { background: var(--sekyro-color-info-soft, var(--sekyro-color-info-soft-fallback)); color: var(--sekyro-color-info-fg, var(--sekyro-color-brand)); }
1166
+ .sekyro-tile--warning { background: var(--sekyro-color-warning-soft, color-mix(in srgb, var(--sekyro-color-warning) 12%, var(--sekyro-color-surface))); color: var(--sekyro-color-warning-fg, var(--sekyro-color-warning)); }
1167
+ .sekyro-tile--success { background: var(--sekyro-color-success-soft, color-mix(in srgb, var(--sekyro-color-success) 14%, var(--sekyro-color-surface))); color: var(--sekyro-color-success-fg, var(--sekyro-color-success)); }
1168
+ /* Still working: the tile breathes (a soft halo of its own colour grows and fades). */
1169
+ .sekyro-tile.is-busy { animation: sekyro-breathe 1.6s ease-in-out infinite; }
1170
+ @keyframes sekyro-breathe {
1171
+ 0%, 100% { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sekyro-color-fg) 5%, transparent), 0 0 0 0 var(--sekyro-color-brand-soft); }
1172
+ 50% { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sekyro-color-fg) 5%, transparent), 0 0 0 10px var(--sekyro-color-brand-soft); }
1173
+ }
1174
+ .sekyro-status__body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1.25rem; flex: 1; padding-block: 1rem 2rem; text-align: center; }
1175
+ .sekyro-root .sekyro-status__text { align-items: center; max-inline-size: 26rem; }
1176
+ .sekyro-status__text .sekyro-notice { text-align: start; align-self: stretch; }
1177
+
1178
+ /* The loading page: quiet bars where the page will be. */
1179
+ .sekyro-skeleton { display: flex; flex-direction: column; gap: 1rem; padding-block: 1.5rem; }
1180
+ .sekyro-skeleton__bar { display: block; block-size: 1.25rem; inline-size: 100%; border-radius: 9999px; background: var(--sekyro-color-sunken); animation: sekyro-pulse 1.4s ease-in-out infinite; }
1181
+ .sekyro-skeleton__bar.is-title { block-size: 2rem; inline-size: 80%; }
1182
+ .sekyro-skeleton__bar.is-short { inline-size: 60%; }
1183
+ .sekyro-skeleton__bar.is-block { block-size: 10rem; margin-block-start: 1.5rem; border-radius: var(--sekyro-radius-card); }
1184
+ @keyframes sekyro-pulse { 50% { opacity: 0.55; } }
1185
+
1186
+ /* ── The modal (terms, leave): a bottom sheet on a phone, centred from 40rem ── */
1187
+ .sekyro-dialog {
1188
+ box-sizing: border-box; inline-size: 100%; max-inline-size: 100%; max-block-size: 88dvh; margin: auto auto 0; padding: 0; border: 0;
1189
+ border-start-start-radius: 20px; border-start-end-radius: 20px; background: var(--sekyro-color-surface); color: var(--sekyro-color-fg);
1190
+ font: var(--sekyro-type-flow-body) var(--sekyro-font); overflow: hidden;
1191
+ }
1192
+ .sekyro-dialog[open] { display: flex; animation: sekyro-sheet var(--sekyro-motion-page) var(--sekyro-ease-out) both; }
1193
+ .sekyro-dialog::backdrop { background: color-mix(in srgb, var(--sekyro-color-stage) 55%, transparent); }
1194
+ @keyframes sekyro-sheet { from { transform: translateY(24px); opacity: 0; } }
1195
+ @media (min-width: 40rem) {
1196
+ .sekyro-dialog { max-inline-size: 30rem; margin: auto; border-radius: 20px; }
1197
+ }
1198
+ .sekyro-dialog__panel { display: flex; flex-direction: column; inline-size: 100%; max-block-size: 88dvh; padding-block-end: max(1rem, env(safe-area-inset-bottom)); }
1199
+ .sekyro-dialog__head { display: flex; align-items: center; gap: 0.75rem; padding-block: 1rem 0.5rem; padding-inline: 1.5rem 1rem; }
1200
+ .sekyro-dialog__title { flex: 1; margin: 0; font: var(--sekyro-type-flow-title) var(--sekyro-font-display); letter-spacing: var(--sekyro-tracking-flow-title); text-wrap: balance; }
1201
+ .sekyro-root [lang="ar"] .sekyro-dialog__title { font-family: var(--sekyro-font-arabic); line-height: 1.4; }
1202
+ .sekyro-dialog__close { flex-shrink: 0; }
1203
+ .sekyro-dialog__body { overflow-y: auto; padding-block: 0.25rem 1rem; padding-inline: 1.5rem; color: var(--sekyro-color-fg-muted); }
1204
+ .sekyro-dialog__body p { margin: 0; }
1205
+ .sekyro-dialog__actions { display: flex; flex-direction: column; gap: 0.75rem; padding-block-start: 0.5rem; padding-inline: 1.5rem; }
1206
+ .sekyro-dialog .sekyro-disc:focus-visible { outline: var(--sekyro-focus); outline-offset: 2px; }
1207
+
1208
+ .sekyro-reference {
1209
+ display: inline-flex; align-items: center; gap: 0.5rem; min-block-size: 44px; padding-inline: 0.75rem; border: 0; border-radius: 9999px; background: none;
1210
+ font: var(--sekyro-type-flow-caption) var(--sekyro-font); font-variant-numeric: tabular-nums; color: var(--sekyro-color-fg-muted); cursor: pointer;
1211
+ }
1212
+ .sekyro-reference > bdi { color: var(--sekyro-color-fg); }
1213
+ .sekyro-reference > .sekyro-glyph { inline-size: 16px; block-size: 16px; }
1214
+ .sekyro-reference.is-copied > span { color: var(--sekyro-color-success); }
1215
+
1216
+ /* ── Lumière: the document camera, edge to edge ────────────────────────── */
1217
+ .sekyro-lm { margin-inline: calc(-1 * var(--sekyro-gutter)); }
1218
+ .sekyro-lm-stage {
1219
+ position: relative; overflow: hidden; block-size: 100svh; min-block-size: 32rem;
1220
+ background: var(--sekyro-color-stage); color: var(--sekyro-color-on-stage);
1221
+ }
1222
+ /* A wide screen keeps a phone-shaped camera, centred. */
1223
+ @media (min-width: 40rem) { .sekyro-lm-stage { block-size: min(100svh, 52rem); max-inline-size: 28rem; margin-inline: auto; border-radius: 16px; } }
1224
+ .sekyro-lm-video { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; object-fit: cover; transition: filter 250ms ease-out; }
1225
+ /* While the photos are read: a light blur (about a third of a full system blur), the scene still recognisable. */
1226
+ .sekyro-lm-stage.is-reading .sekyro-lm-video { filter: blur(6px) brightness(0.92); }
1227
+ /* The camera's view when the last photo was taken, lightly blurred behind the card being read. */
1228
+ .sekyro-lm-scene { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; object-fit: cover; filter: blur(4px) brightness(0.92); animation: sekyro-fade 250ms ease-out both; }
1229
+ .sekyro-lm-frozen { position: absolute; object-fit: cover; animation: sekyro-fade 250ms ease-out both; }
1230
+ @keyframes sekyro-fade { from { opacity: 0; } }
1231
+ .sekyro-lm-overlay { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; pointer-events: none; }
1232
+ .sekyro-lm-ink { stop-color: var(--sekyro-color-stage); }
1233
+ .sekyro-lm-scrim { fill: var(--sekyro-color-stage); fill-opacity: 0.6; }
1234
+ .sekyro-lm-brackets > path {
1235
+ fill: none; stroke: var(--sekyro-color-on-stage); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
1236
+ transition: transform 450ms cubic-bezier(0.2, 0.9, 0.3, 1);
1237
+ }
1238
+ .sekyro-lm-brackets { filter: drop-shadow(0 0 4px color-mix(in srgb, var(--sekyro-color-stage) 40%, transparent)); }
1239
+ .sekyro-lm-brackets.is-coaching > path { stroke: var(--sekyro-color-stage-warning); }
1240
+ .sekyro-lm-brackets.is-locked > path { stroke: var(--sekyro-color-on-camera-success); }
1241
+ .sekyro-lm-brackets.is-locked { filter: drop-shadow(0 0 8px color-mix(in srgb, var(--sekyro-color-on-camera-success) 55%, transparent)); }
1242
+ .sekyro-lm-trace { fill: none; stroke: var(--sekyro-color-on-camera-success); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; animation: sekyro-draw linear forwards; }
1243
+ /* The Lumière signature: one precise aqua line crossing the card (in the reading direction). */
1244
+ .sekyro-lm-slot { position: absolute; overflow: hidden; pointer-events: none; }
1245
+ .sekyro-lm-read {
1246
+ position: absolute; inset-block: 0; inset-inline-start: -6px; inline-size: 12px; mix-blend-mode: screen;
1247
+ animation: sekyro-lm-read 600ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
1248
+ }
1249
+ .sekyro-lm-read::after {
1250
+ content: ""; position: absolute; inset-block: 0; inset-inline-start: 5px; inline-size: 2px;
1251
+ background: var(--sekyro-color-stage-accent); box-shadow: 0 0 5px var(--sekyro-color-stage-accent);
1252
+ }
1253
+ .sekyro-lm-read.is-repeating { animation: sekyro-lm-read 1.3s ease-in-out infinite alternate; }
1254
+ @keyframes sekyro-lm-read { from { transform: translateX(0); } to { transform: translateX(calc(var(--sekyro-guide-w) * var(--sekyro-inline-sign))); } }
1255
+ /* The camera's one instruction, large and white over the ink, above the card; one line at a time. */
1256
+ .sekyro-lm-instruction { position: absolute; inset-inline: 6%; display: flex; flex-direction: column; align-items: center; gap: 0.5rem; text-align: center; transform: translateY(-50%); }
1257
+ .sekyro-lm-instruction > div { display: grid; }
1258
+ .sekyro-lm-line {
1259
+ font: var(--sekyro-type-flow-camera) var(--sekyro-font-display); letter-spacing: var(--sekyro-tracking-flow-camera);
1260
+ color: var(--sekyro-color-on-stage); text-shadow: 0 2px 8px color-mix(in srgb, var(--sekyro-color-stage) 50%, transparent);
1261
+ text-wrap: balance; animation: sekyro-line-in 250ms ease-out 0ms both; transition: opacity 100ms ease-out;
1262
+ }
1263
+ .sekyro-root [lang="ar"] .sekyro-lm-line { font-family: var(--sekyro-font-arabic); line-height: 1.4; }
1264
+ .sekyro-lm-line.is-leaving { opacity: 0; }
1265
+ @keyframes sekyro-line-in { from { opacity: 0; transform: translateY(4px); } }
1266
+ .sekyro-lm-attempts { margin: 0; font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: color-mix(in srgb, var(--sekyro-color-on-stage) 80%, transparent); }
1267
+ .sekyro-lm-under { position: absolute; inset-inline: 0; display: flex; justify-content: center; margin: 0; pointer-events: none; }
1268
+ .sekyro-lm-note { align-items: center; gap: 0.75rem; font: var(--sekyro-type-flow-label) var(--sekyro-font); color: color-mix(in srgb, var(--sekyro-color-on-stage) 85%, transparent); animation: sekyro-fade 250ms ease-out 100ms both; }
1269
+ .sekyro-lm-spinner {
1270
+ inline-size: 20px; block-size: 20px; border-radius: 50%; box-sizing: border-box;
1271
+ border: 2.5px solid var(--sekyro-color-stage-accent); border-block-start-color: transparent; animation: sekyro-turn 0.9s linear infinite;
1272
+ }
1273
+ /* "Turn the card": a small card turning over under the slot (front: portrait and lines; back: the code lines). */
1274
+ /* A physical card: it reads left to right in Arabic too. */
1275
+ .sekyro-lm-flip { direction: ltr; perspective: 400px; animation: sekyro-fade 250ms ease-out both; }
1276
+ .sekyro-lm-flip-card { position: relative; inline-size: 64px; transform-style: preserve-3d; animation: sekyro-flip 0.9s ease-in-out 0.3s infinite alternate; }
1277
+ .sekyro-lm-flip.is-toFront .sekyro-lm-flip-card { animation-direction: alternate-reverse; }
1278
+ .sekyro-lm-flip-card { --sekyro-cue: color-mix(in srgb, var(--sekyro-color-on-stage) 85%, transparent); }
1279
+ .sekyro-lm-flip-front, .sekyro-lm-flip-back {
1280
+ position: absolute; inset: 0; border: 1.75px solid var(--sekyro-cue); border-radius: 6px; backface-visibility: hidden;
1281
+ }
1282
+ .sekyro-lm-flip-front::before { content: ""; position: absolute; inset-block-start: 7px; inset-inline-start: 7px; inline-size: 13px; block-size: 17px; border-radius: 2px; border: 1.5px solid var(--sekyro-cue); box-sizing: border-box; }
1283
+ .sekyro-lm-flip-front::after { content: ""; position: absolute; inset-block-start: 9px; inset-inline: 26px 9px; block-size: 2px; border-radius: 2px; background: var(--sekyro-cue); box-shadow: 0 6px 0 var(--sekyro-cue), 0 12px 0 var(--sekyro-cue); }
1284
+ .sekyro-lm-flip-back { transform: rotateY(180deg); }
1285
+ .sekyro-lm-flip-back::after { content: ""; position: absolute; inset-block-end: 9px; inset-inline: 8px; block-size: 2px; border-radius: 2px; background: var(--sekyro-cue); box-shadow: 0 -6px 0 var(--sekyro-cue); }
1286
+ @keyframes sekyro-flip { to { transform: rotateY(180deg); } }
1287
+ /* Frosted controls, the manual shutter and the faces tray. */
1288
+ .sekyro-lm-controls {
1289
+ position: absolute; inset: 0; display: flex; flex-direction: column; align-items: stretch; gap: 1.25rem; pointer-events: none;
1290
+ padding-block: max(0.75rem, env(safe-area-inset-top)) max(0.75rem, env(safe-area-inset-bottom)); padding-inline: 1.25rem;
1291
+ }
1292
+ .sekyro-lm-controls > * { pointer-events: auto; }
1293
+ .sekyro-lm-bar { display: flex; justify-content: space-between; margin-block-end: auto; }
1294
+ .sekyro-glass {
1295
+ display: inline-grid; place-items: center; inline-size: 44px; block-size: 44px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
1296
+ background: color-mix(in srgb, var(--sekyro-color-on-stage) 18%, transparent); color: var(--sekyro-color-on-stage);
1297
+ -webkit-backdrop-filter: blur(20px) saturate(1.6); backdrop-filter: blur(20px) saturate(1.6);
1298
+ }
1299
+ /* Spec 2026-11-06 §3.3: the capture mode switch, a frosted pill with its icon and short label. */
1300
+ .sekyro-glass.sekyro-glass--label {
1301
+ display: inline-flex; gap: 0.5rem; align-items: center; inline-size: auto; block-size: auto; min-block-size: 44px;
1302
+ max-inline-size: 100%; padding-block: 0.5rem; padding-inline: 0.75rem 1rem; border-radius: 9999px; font: inherit; text-align: start;
1303
+ }
1304
+ .sekyro-glass.is-on { background: var(--sekyro-color-on-stage); color: var(--sekyro-color-stage); }
1305
+ .sekyro-glass:focus-visible, .sekyro-shutter:focus-visible { outline: 3px solid var(--sekyro-color-on-stage); outline-offset: 2px; }
1306
+ .sekyro-shutter {
1307
+ align-self: center; inline-size: 74px; block-size: 74px; border: 3px solid color-mix(in srgb, var(--sekyro-color-on-stage) 90%, transparent);
1308
+ border-radius: 50%; background: var(--sekyro-color-on-stage) content-box; padding: 4px; cursor: pointer; box-sizing: border-box;
1309
+ animation: sekyro-fill 350ms var(--sekyro-spring) both;
1310
+ }
1311
+ .sekyro-lm-tray { display: flex; justify-content: center; align-items: flex-end; gap: 1.5rem; margin: 0; padding: 0; list-style: none; }
1312
+ .sekyro-lm-tray > li {
1313
+ display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
1314
+ font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: color-mix(in srgb, var(--sekyro-color-on-stage) 62%, transparent);
1315
+ }
1316
+ .sekyro-lm-tray > li.is-done { color: var(--sekyro-color-on-stage); }
1317
+ .sekyro-lm-thumb {
1318
+ position: relative; inline-size: 58px; block-size: 37px; border-radius: 6px; box-sizing: border-box;
1319
+ border: 1.5px solid var(--sekyro-color-on-camera-success); background: color-mix(in srgb, var(--sekyro-color-on-stage) 12%, transparent);
1320
+ animation: sekyro-fill 400ms var(--sekyro-spring) both;
1321
+ }
1322
+ .sekyro-lm-thumb > img { inline-size: 100%; block-size: 100%; object-fit: cover; border-radius: 4.5px; }
1323
+ .sekyro-lm-check {
1324
+ position: absolute; inset-block-start: -6px; inset-inline-end: -6px; inline-size: 18px; block-size: 18px; border-radius: 50%;
1325
+ background: var(--sekyro-color-on-camera-success); fill: none; stroke: var(--sekyro-color-on-stage); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
1326
+ }
1327
+ .sekyro-lm-error {
1328
+ display: flex; flex-direction: column; gap: 0.5rem; padding: 1rem; border-radius: 16px;
1329
+ background: color-mix(in srgb, var(--sekyro-color-stage) 88%, transparent); color: var(--sekyro-color-on-stage);
1330
+ }
1331
+ .sekyro-lm-error > p { margin: 0; }
1332
+ /* Design 2026-11-04 §5: "Upload a photo instead" over the camera, under the tray (a glass pill). */
1333
+ .sekyro-lm-upload {
1334
+ align-self: center; min-block-size: 44px; padding-block: 0.5rem; padding-inline: 1.25rem; border: 0; border-radius: 999px; cursor: pointer;
1335
+ font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: var(--sekyro-color-on-stage);
1336
+ background: color-mix(in srgb, var(--sekyro-color-on-stage) 18%, transparent);
1337
+ }
1338
+ .sekyro-lm-upload:focus-visible { outline: 3px solid var(--sekyro-color-ring); outline-offset: 2px; }
1339
+ /* Design 2026-11-04 §6.4: the original and the adjusted portrait side by side (the order follows the writing direction). */
1340
+ .sekyro-portrait-pair { display: flex; flex-direction: row; gap: 0.75rem; }
1341
+ .sekyro-portrait-pair__item { flex: 1 1 0; min-inline-size: 0; margin: 0; display: flex; flex-direction: column; gap: 0.375rem; }
1342
+ .sekyro-portrait-pair__item > img {
1343
+ inline-size: 100%; aspect-ratio: 3 / 4; object-fit: contain; border-radius: var(--sekyro-radius);
1344
+ border: 1px solid var(--sekyro-color-line); background: var(--sekyro-color-surface);
1345
+ }
1346
+ .sekyro-portrait-pair__item > figcaption { text-align: center; }
1347
+ .sekyro-portrait-fixes { margin: 0; padding-inline-start: 1.25rem; }
1348
+
1349
+ /* ── The face camera (face-camera.tsx): the oval cut from the ink, its ring of ticks and the running light ── */
1350
+ .sekyro-fc-video { transform: scaleX(-1); }
1351
+ /* The back camera (assisted capture) is not a selfie: no mirror. */
1352
+ .sekyro-fc-video.is-rear { transform: none; }
1353
+ .sekyro-fc-still { animation: sekyro-fade 250ms ease-out both; }
1354
+ .sekyro-fc-scrim { fill: var(--sekyro-color-stage); fill-opacity: 0.82; }
1355
+ /* Liveness v7 §4.4: while a screen-ramp pastel fills the viewport, the white instruction and note sit on a band of the
1356
+ * scrim's ink at the scrim's opacity (white keeps at least 4.5:1 over the brightest pastel: screen-ramp-contrast.test). */
1357
+ .sekyro-fc[data-ramp] .sekyro-lm-line,
1358
+ .sekyro-fc[data-ramp] .sekyro-lm-note {
1359
+ background: color-mix(in srgb, var(--sekyro-color-stage) 82%, transparent);
1360
+ border-radius: 999px;
1361
+ padding-block: 0.25rem;
1362
+ padding-inline: 1rem;
1363
+ }
1364
+ /* The wash (screen-ramp-layer.tsx) lights the whole screen, its cover fills the stage over the camera; the ink around
1365
+ * the oval steps aside so the ring sits on the colour. */
1366
+ .sekyro-fc[data-ramp] .sekyro-fc-scrim { visibility: hidden; }
1367
+ .sekyro-fc-rim { fill: none; stroke: color-mix(in srgb, var(--sekyro-color-on-stage) 35%, transparent); stroke-width: 1.5; }
1368
+ .sekyro-fc-ticks { fill: none; stroke: color-mix(in srgb, var(--sekyro-color-on-stage) 28%, transparent); stroke-width: 3; stroke-linecap: round; }
1369
+ .sekyro-fc-ticks.is-done { stroke: var(--sekyro-color-on-camera-success); filter: drop-shadow(0 0 4px color-mix(in srgb, var(--sekyro-color-on-camera-success) 60%, transparent)); }
1370
+ .sekyro-fc-ticks.is-light { stroke: var(--sekyro-color-stage-accent); }
1371
+ .sekyro-fc-fade { stop-color: var(--sekyro-color-on-stage); }
1372
+ .sekyro-fc-sweep { animation: sekyro-turn 2.2s linear infinite; }
1373
+ .sekyro-fc-panel {
1374
+ display: flex; flex-direction: column; gap: 0.75rem; padding: 1rem; border-radius: 16px;
1375
+ background: var(--sekyro-color-surface); color: var(--sekyro-color-fg);
1376
+ }
1377
+ .sekyro-fc-checks { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem 1rem; margin: 0; padding: 0; list-style: none; }
1378
+ .sekyro-fc-checks > li {
1379
+ display: flex; align-items: center; gap: 0.375rem;
1380
+ font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: color-mix(in srgb, var(--sekyro-color-on-stage) 70%, transparent);
1381
+ }
1382
+ .sekyro-fc-checks > li.is-met { color: var(--sekyro-color-on-stage); }
1383
+ .sekyro-fc-mark {
1384
+ display: inline-grid; place-items: center; inline-size: 16px; block-size: 16px; border-radius: 50%; box-sizing: border-box;
1385
+ border: 1.5px solid currentColor;
1386
+ }
1387
+ .sekyro-fc-mark > svg { inline-size: 14px; block-size: 14px; fill: none; stroke: transparent; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
1388
+ .sekyro-fc-checks > li.is-met .sekyro-fc-mark { border-color: var(--sekyro-color-on-camera-success); background: var(--sekyro-color-on-camera-success); }
1389
+ .sekyro-fc-checks > li.is-met .sekyro-fc-mark > svg { stroke: var(--sekyro-color-stage); }
1390
+ /* A criterion the last photo failed (the server's report), until the gate holds it: the row to fix. */
1391
+ .sekyro-fc-checks > li.is-flagged { color: var(--sekyro-color-on-stage); }
1392
+ .sekyro-fc-checks > li.is-flagged .sekyro-fc-mark { border-color: var(--sekyro-color-warning); border-width: 2px; }
1393
+
1394
+ /* The face capture (the 0.1 stage) inside the flow: the instruction on the flow's camera scale. */
1395
+ .sekyro-verification .sekyro-stage__guidance-text { font: var(--sekyro-type-flow-camera) var(--sekyro-font-display); letter-spacing: var(--sekyro-tracking-flow-camera); }
1396
+ .sekyro-root [lang="ar"] .sekyro-stage__guidance-text { font-family: var(--sekyro-font-arabic); }
1397
+
1398
+ /* Over the camera, the scrim is the Sekyro navy and captions are white, in light and dark alike: inside a stage,
1399
+ * the `fg` (scrim) and `surface` (caption) tokens the 0.1 stage rules paint with are remapped. */
1400
+ .sekyro-verification .sekyro-stage {
1401
+ --sekyro-color-fg: var(--sekyro-color-stage);
1402
+ --sekyro-color-surface: var(--sekyro-color-on-stage);
1403
+ }
1404
+
1405
+ @media (prefers-reduced-motion: reduce) {
1406
+ .sekyro-fc-sweep, .sekyro-fc-still, .sekyro-page > *, .sekyro-otp-digit, .sekyro-otp-row.is-shaking, .sekyro-lm-line, .sekyro-lm-thumb, .sekyro-shutter { animation: none; }
1407
+ .sekyro-mark__read { animation: none; transform: translate(calc(var(--sekyro-read-w) * 0.62), 0); }
1408
+ .sekyro-mark__arc { animation: none; stroke-dashoffset: 0.45; }
1409
+ .sekyro-lm-read, .sekyro-lm-flip-card { animation: none; }
1410
+ .sekyro-lm-flip-card { transform: rotateY(180deg); }
1411
+ .sekyro-lm-read.is-repeating { transform: translateX(calc(var(--sekyro-guide-w) * 0.5 * var(--sekyro-inline-sign))); }
1412
+ .sekyro-outcome__glyph { animation: none; stroke-dashoffset: 0; }
1413
+ .sekyro-outcome__ring, .sekyro-outcome__disc, .sekyro-outcome-tile, .sekyro-dialog[open], .sekyro-skeleton__bar, .sekyro-handoff__pulse { animation: none; }
1414
+ .sekyro-tile.is-busy { animation: none; }
1415
+ .sekyro-lm-brackets > path, .sekyro-progress__bar::before, .sekyro-root .sekyro-btn, .sekyro-card { transition: none; }
1416
+ .sekyro-root .sekyro-btn:active, .sekyro-card:active { transform: none; }
1417
+ .sekyro-lm-trace { animation: none; stroke-dashoffset: 0; }
1418
+ }
1419
+ /* A masked number or address stays on one line, left to right. */
1420
+ .sekyro-root bdi.sekyro-mono { white-space: nowrap; font-family: inherit; font-variant-numeric: tabular-nums; }
1421
+
1422
+ /* Web live MRZ (plan Task 10): the band the on-device reader watches, at the bottom of the guide. Decorative — the
1423
+ polite pill carries the state; the pulse stops under reduced motion. */
1424
+ .sekyro-lm-mrz { position: absolute; inset-inline: 9%; inset-block-end: 22%; block-size: 22%; border: 2px solid var(--sekyro-color-brand); border-radius: 6px; background: color-mix(in srgb, var(--sekyro-color-brand) 12%, transparent); animation: sekyro-lm-mrz-pulse 1.4s ease-in-out infinite; pointer-events: none; }
1425
+ .sekyro-lm-mrz.is-page { inset-block-end: 18%; block-size: 16%; }
1426
+ .sekyro-lm-mrz.is-valid { border-color: var(--sekyro-color-success); animation: none; }
1427
+ @keyframes sekyro-lm-mrz-pulse { 50% { opacity: 0.55; } }
1428
+ @media (prefers-reduced-motion: reduce) { .sekyro-lm-mrz { animation: none; } }
1429
+ /* The choice screens on the step's rhythm (the 0.1 drop-in keeps its own). */
1430
+ .sekyro-flow .sekyro-choice { flex: 1; gap: var(--sekyro-size-step-gap); padding-block-start: 1.5rem; }
1431
+ /* Flow model 2026-10-23: the identity summary, the handoff QR. */
1432
+ .sekyro-summary__source {
1433
+ display: inline-flex; align-self: flex-start; margin: 0; padding-block: 0.25rem; padding-inline: 0.625rem; border-radius: 9999px;
1434
+ background: var(--sekyro-color-sunken); font: var(--sekyro-type-flow-caption) var(--sekyro-font); color: var(--sekyro-color-fg-muted);
1435
+ }
1436
+ .sekyro-handoff__waiting { display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin: 0; text-align: center; font: var(--sekyro-type-flow-label) var(--sekyro-font); color: var(--sekyro-color-fg-muted); }
1437
+ .sekyro-handoff__pulse { inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--sekyro-color-brand); animation: sekyro-pulse 1.4s ease-in-out infinite; }.sekyro-summary { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; padding: 1rem; border: 1px solid var(--sekyro-color-line-subtle); border-radius: var(--sekyro-radius-card); }
1438
+ .sekyro-summary__portrait { inline-size: 5.5rem; block-size: 7rem; object-fit: cover; border-radius: 10px; }
1439
+ .sekyro-summary__list { display: grid; gap: 0.75rem; margin: 0; flex: 1 1 12rem; }
1440
+ .sekyro-summary__row { display: grid; gap: 0.125rem; }
1441
+ .sekyro-summary__row dt { font: var(--sekyro-type-flow-caption) var(--sekyro-font); }
1442
+ .sekyro-summary__row dd { margin: 0; color: var(--sekyro-color-fg); font: var(--sekyro-type-flow-action) var(--sekyro-font); font-variant-numeric: tabular-nums; }
1443
+ /* The handoff QR: always navy modules on a white tile, in dark mode and under a partner theme too (phone cameras read
1444
+ dark-on-light codes best). The camera-stage pair is fixed Sekyro navy and white: no theme or branding sets it. */
1445
+ .sekyro-qr { inline-size: 12rem; block-size: 12rem; align-self: center; padding: 0.75rem; border: 1px solid var(--sekyro-color-line-subtle); border-radius: var(--sekyro-radius-card); background: var(--sekyro-color-on-stage); }
1446
+ .sekyro-qr__bg { fill: var(--sekyro-color-on-stage); }
1447
+ .sekyro-qr__fg { fill: var(--sekyro-color-stage); }
1448
+ a.sekyro-btn { text-decoration: none; }
1449
+ /* WhatsApp and SMS as equals: one row, two buttons of the same kind and width (Salem 2026-11-05). */
1450
+ .sekyro-channel-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; }
1451
+ .sekyro-channel-row > .sekyro-btn { padding-inline: 0.75rem; }
1452
+
1453
+ /* @sekyro/elements: the element is a block, like the flow's own root. */
1454
+ sekyro-verification { display: block; }
1455
+ sekyro-verification:not(:defined) { display: none; }
1456
+
1457
+ /* Host stylesheets reset whole pages (Bootstrap's reboot, Tailwind's preflight): the flow keeps the browser's own
1458
+ defaults it was built on. Element selectors only, so every rule of the flow's own (a class) still wins. */
1459
+ sekyro-verification *,
1460
+ sekyro-verification *::before,
1461
+ sekyro-verification *::after { box-sizing: content-box; }
1462
+ /* The inherited text properties start from the browser's defaults at the element, whatever the page's body sets
1463
+ (Bootstrap's line height of 1.5, a framework's letter spacing): the flow sets its own fonts and colours below it. */
1464
+ sekyro-verification {
1465
+ font-size: medium;
1466
+ font-weight: normal;
1467
+ font-style: normal;
1468
+ line-height: normal;
1469
+ letter-spacing: normal;
1470
+ word-spacing: normal;
1471
+ text-align: start;
1472
+ text-indent: 0;
1473
+ text-transform: none;
1474
+ white-space: normal;
1475
+ }