@rhinestone/deposit-modal 0.3.0-alpha.9 → 0.3.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 (39) hide show
  1. package/README.md +76 -0
  2. package/dist/{DepositModalReown-I7I3KLD2.mjs → DepositModalReown-6SUEC5IU.mjs} +4 -4
  3. package/dist/{DepositModalReown-XUA47RYZ.cjs → DepositModalReown-DNW4GH6L.cjs} +7 -7
  4. package/dist/{QRCode-KG47KTGX.cjs → QRCode-5DXFNKI2.cjs} +1 -1
  5. package/dist/{QRCode-YJ3EGWQS.mjs → QRCode-WUC652SH.mjs} +1 -1
  6. package/dist/{WithdrawModalReown-KN2DGOXR.mjs → WithdrawModalReown-7UAGSOSU.mjs} +4 -4
  7. package/dist/{WithdrawModalReown-JATYMQYP.cjs → WithdrawModalReown-OUWBSKSM.cjs} +7 -7
  8. package/dist/{constants-DqVn968d.d.ts → caip-CrQ2KKU-.d.cts} +11 -1
  9. package/dist/{constants-DqVn968d.d.cts → caip-CrQ2KKU-.d.ts} +11 -1
  10. package/dist/{chunk-G5Q4QBWX.cjs → chunk-2SMS542Q.cjs} +109 -102
  11. package/dist/{chunk-KIPKYPNF.cjs → chunk-33H6O5UU.cjs} +6 -16
  12. package/dist/{chunk-SZIYS42B.mjs → chunk-6YRDD462.mjs} +63 -3
  13. package/dist/{chunk-OISMGA2L.mjs → chunk-GPSBM66J.mjs} +2 -12
  14. package/dist/{chunk-TJG2AFPS.mjs → chunk-KAWJABTW.mjs} +1048 -540
  15. package/dist/{chunk-4BUMVXPS.mjs → chunk-KJ2RR2D4.mjs} +1829 -584
  16. package/dist/{chunk-7JIDIX27.cjs → chunk-MILJQWPT.cjs} +73 -13
  17. package/dist/{chunk-MMXUBBGK.cjs → chunk-RABZINV3.cjs} +1032 -524
  18. package/dist/{chunk-KE4MRCFN.mjs → chunk-TKQYTBU6.mjs} +21 -14
  19. package/dist/{chunk-ZVG4JDKZ.cjs → chunk-VVJAIMKB.cjs} +1881 -636
  20. package/dist/constants.cjs +6 -2
  21. package/dist/constants.d.cts +1 -1
  22. package/dist/constants.d.ts +1 -1
  23. package/dist/constants.mjs +5 -1
  24. package/dist/deposit.cjs +4 -4
  25. package/dist/deposit.d.cts +2 -2
  26. package/dist/deposit.d.ts +2 -2
  27. package/dist/deposit.mjs +3 -3
  28. package/dist/index.cjs +19 -6
  29. package/dist/index.d.cts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.mjs +20 -7
  32. package/dist/styles.css +685 -75
  33. package/dist/{types-D8Q4TMk7.d.cts → types-BMcGO5k_.d.cts} +56 -2
  34. package/dist/{types-D8Q4TMk7.d.ts → types-BMcGO5k_.d.ts} +56 -2
  35. package/dist/withdraw.cjs +4 -4
  36. package/dist/withdraw.d.cts +2 -2
  37. package/dist/withdraw.d.ts +2 -2
  38. package/dist/withdraw.mjs +3 -3
  39. package/package.json +41 -17
package/dist/styles.css CHANGED
@@ -284,6 +284,11 @@
284
284
  /* Cap the modal at 600px (or viewport-40 on tiny screens) so long lists
285
285
  scroll inside instead of growing the modal. */
286
286
  max-height: min(600px, calc(100vh - 40px));
287
+ /* Explicit 0 (not the `auto` default) so the min-height transition
288
+ below has a definite starting value when :has() rules later raise
289
+ it to the iframe-mounted height. Transitions from `auto` are
290
+ unreliable in browsers and tend to apply instantly. */
291
+ min-height: 0;
287
292
  display: flex;
288
293
  flex-direction: column;
289
294
  margin: 20px;
@@ -292,7 +297,18 @@
292
297
  border: 1px solid var(--rs-border);
293
298
  border-radius: var(--rs-radius-lg);
294
299
  transform: scale(0.95);
295
- transition: transform 0.2s ease;
300
+ transition:
301
+ transform 0.2s ease,
302
+ /* Smooth resize when the user moves between steps with different
303
+ widths (e.g. ConnectStep 400 → Connect-via-Swapped 469) instead of
304
+ a hard pop. */
305
+ max-width 240ms cubic-bezier(0.22, 1, 0.36, 1),
306
+ /* Same for height: when a flow starts that pre-reserves the iframe
307
+ size (via the min-height :has() rules below), grow smoothly from
308
+ the previous step's height instead of jumping. Min-height is on
309
+ modal-content rather than modal-body so the transitioned property
310
+ lives on an element that survives step swaps. */
311
+ min-height 280ms cubic-bezier(0.22, 1, 0.36, 1);
296
312
  }
297
313
 
298
314
  .rs-modal-content[data-theme="dark"] {
@@ -375,21 +391,17 @@
375
391
  padding-inline: 16px;
376
392
  }
377
393
 
378
- .rs-modal-body::-webkit-scrollbar {
379
- width: 6px;
380
- }
381
-
382
- .rs-modal-body::-webkit-scrollbar-track {
383
- background: transparent;
384
- }
385
-
386
- .rs-modal-body::-webkit-scrollbar-thumb {
387
- background-color: var(--rs-surface-hover);
388
- border-radius: var(--rs-radius-full);
394
+ /* Scrollbars are hidden throughout the modal UI. The portfolio list
395
+ (.rs-asset-list) is the sole exception — it keeps a visible scrollbar since
396
+ it's a long, independently-scrolling list. The :not() exemption also keeps
397
+ this rule's specificity above the per-container scrollbar rules elsewhere. */
398
+ .rs-modal *:not(.rs-asset-list) {
399
+ scrollbar-width: none;
389
400
  }
390
401
 
391
- .rs-modal-body::-webkit-scrollbar-thumb:hover {
392
- background-color: var(--rs-muted-foreground);
402
+ .rs-modal *:not(.rs-asset-list)::-webkit-scrollbar {
403
+ width: 0;
404
+ height: 0;
393
405
  }
394
406
 
395
407
  /* =============================================================================
@@ -1095,7 +1107,10 @@
1095
1107
  display: flex;
1096
1108
  flex-direction: column;
1097
1109
  gap: 4px;
1098
- max-height: 320px;
1110
+ /* Figma's asset list is 284px — exactly 4 rows (4×68 + 3×4 gaps). Cap here
1111
+ so wallets with many assets scroll inside instead of growing the modal
1112
+ past the design's height. */
1113
+ max-height: 284px;
1099
1114
  overflow-y: auto;
1100
1115
  overscroll-behavior: contain;
1101
1116
  /* Pull rows back to the row's natural left edge inside a scrollable
@@ -1300,6 +1315,11 @@
1300
1315
  justify-content: center;
1301
1316
  gap: 4px;
1302
1317
  width: 100%;
1318
+ /* `border-box` so the 16px side padding counts INTO the 100% width
1319
+ instead of adding 32px on top of it (which otherwise pushes the
1320
+ footer past containers with their own horizontal padding — e.g.
1321
+ the tracker — and paints a phantom horizontal scrollbar). */
1322
+ box-sizing: border-box;
1303
1323
  padding: 0 16px 16px;
1304
1324
  font-size: 11px;
1305
1325
  font-weight: 500;
@@ -1660,6 +1680,21 @@
1660
1680
  manages the vertical rhythm between body slot and powered-by. */
1661
1681
  padding: 0;
1662
1682
  gap: 16px;
1683
+ /* Each screen fades in on mount so step-to-step transitions feel
1684
+ progressive instead of a hard swap. Short enough that the user
1685
+ doesn't perceive a delay; long enough to look intentional. */
1686
+ animation: rs-screen-enter 180ms ease-out;
1687
+ }
1688
+
1689
+ @keyframes rs-screen-enter {
1690
+ from {
1691
+ opacity: 0;
1692
+ transform: translateY(4px);
1693
+ }
1694
+ to {
1695
+ opacity: 1;
1696
+ transform: translateY(0);
1697
+ }
1663
1698
  }
1664
1699
 
1665
1700
  /* Body slot — direct child of .rs-screen. Always uses a 16px internal
@@ -2782,7 +2817,7 @@
2782
2817
  .rs-withdraw-dropdown-arrow {
2783
2818
  width: 24px;
2784
2819
  height: 24px;
2785
- color: var(--rs-icon-secondary);
2820
+ color: #9f9fa9;
2786
2821
  transition: transform 0.15s;
2787
2822
  }
2788
2823
 
@@ -2968,11 +3003,13 @@
2968
3003
  align-items: center;
2969
3004
  justify-content: space-between;
2970
3005
  gap: 6px;
3006
+ white-space: nowrap;
2971
3007
  }
2972
3008
 
2973
3009
  .rs-deposit-address-min {
2974
3010
  display: inline-flex;
2975
3011
  align-items: center;
3012
+ flex-shrink: 0;
2976
3013
  gap: 4px;
2977
3014
  font-size: 11px;
2978
3015
  font-weight: 500;
@@ -2980,8 +3017,8 @@
2980
3017
  }
2981
3018
 
2982
3019
  .rs-deposit-address-min-icon {
2983
- width: 16px;
2984
- height: 16px;
3020
+ width: 12px;
3021
+ height: 12px;
2985
3022
  flex-shrink: 0;
2986
3023
  color: var(--rs-icon-secondary);
2987
3024
  }
@@ -3005,6 +3042,7 @@
3005
3042
  border: none;
3006
3043
  cursor: pointer;
3007
3044
  font-family: inherit;
3045
+ line-height: normal;
3008
3046
  color: var(--rs-muted);
3009
3047
  text-align: left;
3010
3048
  }
@@ -3085,7 +3123,7 @@
3085
3123
  display: flex;
3086
3124
  align-items: center;
3087
3125
  gap: 8px;
3088
- padding-top: 12px;
3126
+ padding-top: 8px;
3089
3127
  font-size: 12px;
3090
3128
  color: var(--rs-muted);
3091
3129
  }
@@ -3166,7 +3204,10 @@
3166
3204
  align-items: center;
3167
3205
  gap: 8px;
3168
3206
  width: 100%;
3169
- padding: 12px;
3207
+ /* 11px vertical (not 12) so the 1px border lands the input at Figma's
3208
+ 48px total height — Figma draws the stroke inside the box, CSS adds it
3209
+ outside. Horizontal stays 12px to match the design. */
3210
+ padding: 11px 12px;
3170
3211
  background: var(--rs-surface-subtle);
3171
3212
  border-radius: 8px;
3172
3213
  border: 1px solid var(--rs-surface-subtle);
@@ -3205,7 +3246,7 @@
3205
3246
  .rs-deposit-address-dropdown-chevron {
3206
3247
  width: 24px;
3207
3248
  height: 24px;
3208
- color: var(--rs-icon-secondary);
3249
+ color: #9f9fa9;
3209
3250
  margin-left: auto;
3210
3251
  flex-shrink: 0;
3211
3252
  transition: transform 0.15s ease;
@@ -3226,10 +3267,10 @@
3226
3267
  border: 1px solid var(--rs-surface-subtle);
3227
3268
  border-radius: var(--rs-radius-sm);
3228
3269
  box-shadow: var(--rs-shadow-dropdown);
3229
- padding: 12px;
3270
+ padding: 8px;
3230
3271
  display: flex;
3231
3272
  flex-direction: column;
3232
- gap: 16px;
3273
+ gap: 0;
3233
3274
  max-height: 240px;
3234
3275
  overflow-y: auto;
3235
3276
  overscroll-behavior: none;
@@ -3241,8 +3282,8 @@
3241
3282
  align-items: center;
3242
3283
  gap: 6px;
3243
3284
  width: 100%;
3244
- padding: 0;
3245
- border-radius: calc(var(--rs-radius-sm) - 2px);
3285
+ padding: 8px 4px;
3286
+ border-radius: 4px;
3246
3287
  border: none;
3247
3288
  background: transparent;
3248
3289
  color: var(--rs-foreground);
@@ -3251,12 +3292,12 @@
3251
3292
  line-height: normal;
3252
3293
  cursor: pointer;
3253
3294
  text-align: left;
3254
- transition: opacity 0.1s;
3295
+ transition: background-color 0.1s;
3255
3296
  font-family: inherit;
3256
3297
  }
3257
3298
 
3258
3299
  .rs-deposit-address-dropdown-item:hover {
3259
- opacity: 0.7;
3300
+ background: var(--rs-surface);
3260
3301
  }
3261
3302
 
3262
3303
  .rs-deposit-address-dropdown-item--active {
@@ -3274,39 +3315,18 @@
3274
3315
  border-radius: 8px;
3275
3316
  }
3276
3317
 
3277
- /* Mid-refetch: dim the address/QR and block interaction so a stale
3278
- registration can't be copied or scanned until setup is ready again. */
3279
- .rs-deposit-address-well--updating {
3280
- opacity: 0.4;
3281
- pointer-events: none;
3282
- filter: grayscale(0.3);
3283
- transition: opacity 0.15s;
3284
- }
3285
-
3286
- .rs-deposit-address-updating {
3287
- display: flex;
3288
- align-items: center;
3289
- justify-content: center;
3290
- gap: 8px;
3291
- width: 100%;
3292
- padding: 10px 12px;
3293
- font-size: 14px;
3294
- font-weight: 500;
3295
- color: var(--rs-muted);
3296
- }
3297
-
3298
3318
  .rs-deposit-address-qr {
3299
3319
  display: flex;
3300
3320
  align-items: center;
3301
3321
  justify-content: center;
3302
- padding: 12px;
3322
+ padding: 16px;
3303
3323
  }
3304
3324
 
3305
3325
  .rs-deposit-address-qr canvas,
3306
3326
  .rs-deposit-address-qr svg {
3307
3327
  display: block;
3308
- width: 200px;
3309
- height: 200px;
3328
+ width: 190px;
3329
+ height: 190px;
3310
3330
  }
3311
3331
 
3312
3332
  .rs-deposit-address-value {
@@ -3323,6 +3343,61 @@
3323
3343
  word-break: break-all;
3324
3344
  }
3325
3345
 
3346
+ /* Visually hidden but exposed to assistive tech — used by the skeleton's
3347
+ "Preparing…" status, whose visual placeholders are all aria-hidden. */
3348
+ .rs-sr-only {
3349
+ position: absolute;
3350
+ width: 1px;
3351
+ height: 1px;
3352
+ padding: 0;
3353
+ margin: -1px;
3354
+ overflow: hidden;
3355
+ clip: rect(0, 0, 0, 0);
3356
+ white-space: nowrap;
3357
+ border: 0;
3358
+ }
3359
+
3360
+ /* Loading placeholders for DepositAddressSkeleton — grey blocks that pulse
3361
+ while the smart account / deposit address are being prepared. Uses
3362
+ --color-gray4 (zinc-200 light / zinc-800 dark) so it reads on the well in
3363
+ both themes. */
3364
+ .rs-skeleton {
3365
+ background: var(--color-gray4);
3366
+ border-radius: 8px;
3367
+ animation: rs-skeleton-pulse 1.6s ease-in-out infinite;
3368
+ }
3369
+
3370
+ .rs-skeleton-qr {
3371
+ width: 190px;
3372
+ height: 190px;
3373
+ }
3374
+
3375
+ .rs-skeleton-address {
3376
+ height: 12px;
3377
+ margin: 0 16px 12px;
3378
+ border-radius: 8px;
3379
+ }
3380
+
3381
+ /* Inline placeholder sized to the fee value (e.g. "$0.04") while the
3382
+ pre-deposit quote resolves. Stays put if the quote fails. */
3383
+ .rs-skeleton-fee {
3384
+ display: inline-block;
3385
+ width: 36px;
3386
+ height: 13px;
3387
+ border-radius: 4px;
3388
+ vertical-align: middle;
3389
+ }
3390
+
3391
+ @keyframes rs-skeleton-pulse {
3392
+ 0%,
3393
+ 100% {
3394
+ opacity: 1;
3395
+ }
3396
+ 50% {
3397
+ opacity: 0.5;
3398
+ }
3399
+ }
3400
+
3326
3401
  .rs-deposit-address-copy {
3327
3402
  display: flex;
3328
3403
  align-items: center;
@@ -3336,6 +3411,7 @@
3336
3411
  color: var(--rs-foreground);
3337
3412
  font-size: 14px;
3338
3413
  font-weight: 500;
3414
+ line-height: normal;
3339
3415
  font-family: inherit;
3340
3416
  cursor: pointer;
3341
3417
  transition: background-color 0.15s;
@@ -3440,8 +3516,8 @@
3440
3516
  .rs-deposit-notifications {
3441
3517
  position: absolute;
3442
3518
  bottom: 12px;
3443
- left: 12px;
3444
- right: 12px;
3519
+ left: 0;
3520
+ right: 0;
3445
3521
  z-index: 10;
3446
3522
  display: flex;
3447
3523
  flex-direction: column;
@@ -3498,7 +3574,8 @@
3498
3574
  justify-content: center;
3499
3575
  }
3500
3576
 
3501
- .rs-deposit-notification-badge svg {
3577
+ .rs-deposit-notification-badge--complete svg,
3578
+ .rs-deposit-notification-badge--failed svg {
3502
3579
  width: 20px;
3503
3580
  height: 20px;
3504
3581
  }
@@ -3518,9 +3595,29 @@
3518
3595
  color: var(--rs-icon-secondary);
3519
3596
  }
3520
3597
 
3521
- .rs-deposit-notification-badge--processing .rs-spinner {
3598
+ .rs-deposit-notification-spinner {
3522
3599
  width: 42px;
3523
3600
  height: 42px;
3601
+ animation: rs-spin 1s linear infinite;
3602
+ }
3603
+
3604
+ /* Spinner ring/arc colors flip with the theme. Light: a faint zinc-200 ring
3605
+ with a zinc-600 arc on the near-white card. Dark: the Figma values — a
3606
+ zinc-300 ring with a zinc-600 arc on the #18181b card. */
3607
+ .rs-deposit-notification-spinner-track {
3608
+ stroke: #e4e4e7;
3609
+ }
3610
+
3611
+ .rs-deposit-notification-spinner-head {
3612
+ stroke: #52525c;
3613
+ }
3614
+
3615
+ .rs-modal[data-theme="dark"] .rs-deposit-notification-spinner-track {
3616
+ stroke: #d4d4d8;
3617
+ }
3618
+
3619
+ .rs-modal[data-theme="dark"] .rs-deposit-notification-spinner-head {
3620
+ stroke: #52525c;
3524
3621
  }
3525
3622
 
3526
3623
  .rs-deposit-notification-content {
@@ -3968,30 +4065,13 @@
3968
4065
  padding-right: 2px;
3969
4066
  }
3970
4067
 
3971
- .rs-history-list::-webkit-scrollbar {
3972
- width: 6px;
3973
- }
3974
-
3975
- .rs-history-list::-webkit-scrollbar-thumb {
3976
- background-color: var(--rs-surface-hover);
3977
- border-radius: var(--rs-radius-full);
3978
- }
3979
-
3980
- .rs-history-list::-webkit-scrollbar-thumb:hover {
3981
- background-color: var(--rs-muted-foreground);
3982
- }
3983
-
3984
- .rs-history-list::-webkit-scrollbar-track {
3985
- background: transparent;
3986
- }
3987
-
3988
4068
  /* Card */
3989
4069
  .rs-history-card {
3990
4070
  width: 100%;
3991
4071
  display: flex;
3992
4072
  flex-direction: column;
3993
- gap: 16px;
3994
- padding: 16px 12px;
4073
+ gap: 0;
4074
+ padding: 12px 8px;
3995
4075
  background: var(--rs-surface-subtle);
3996
4076
  border: none;
3997
4077
  border-radius: 8px;
@@ -4106,12 +4186,38 @@
4106
4186
  white-space: nowrap;
4107
4187
  }
4108
4188
 
4189
+ /* Collapsing wrapper that animates the detail block between closed/open. */
4190
+ .rs-history-card-panel {
4191
+ display: grid;
4192
+ grid-template-rows: 0fr;
4193
+ transition: grid-template-rows 0.25s ease;
4194
+ }
4195
+
4196
+ .rs-history-card--expanded .rs-history-card-panel {
4197
+ grid-template-rows: 1fr;
4198
+ }
4199
+
4200
+ .rs-history-card-panel-inner {
4201
+ overflow: hidden;
4202
+ min-height: 0;
4203
+ /* Keep the collapsed panel (and its tx link) out of the tab order.
4204
+ visibility stays "visible" through the collapse so the content is
4205
+ present during the height animation, then flips hidden at the end. */
4206
+ visibility: hidden;
4207
+ transition: visibility 0.25s;
4208
+ }
4209
+
4210
+ .rs-history-card--expanded .rs-history-card-panel-inner {
4211
+ visibility: visible;
4212
+ }
4213
+
4109
4214
  /* Expanded detail block under the row. */
4110
4215
  .rs-history-card-details {
4111
4216
  display: flex;
4112
4217
  flex-direction: column;
4113
4218
  gap: 8px;
4114
4219
  width: 100%;
4220
+ padding-top: 16px;
4115
4221
  }
4116
4222
 
4117
4223
  .rs-history-card-link {
@@ -4301,6 +4407,12 @@
4301
4407
  gap: 8px;
4302
4408
  }
4303
4409
 
4410
+ /* Figma gives subtitle headers a 12px icon→title gap (vs 8px for title-only
4411
+ headers like the QR screen). */
4412
+ .rs-body-header:has(.rs-body-header-subtitle) {
4413
+ gap: 12px;
4414
+ }
4415
+
4304
4416
  .rs-body-header-icon {
4305
4417
  display: inline-flex;
4306
4418
  align-items: center;
@@ -4349,11 +4461,81 @@
4349
4461
  .rs-body-header-subtitle {
4350
4462
  font-size: 14px;
4351
4463
  font-weight: 500;
4352
- line-height: 1.4;
4464
+ line-height: normal;
4353
4465
  color: var(--rs-muted);
4354
4466
  margin: 0;
4355
4467
  }
4356
4468
 
4469
+ /* Ticker — per-digit odometer-style animation for the live timer.
4470
+ Each slot clips its content; the outgoing digit slides up and out while
4471
+ the incoming digit slides up from below. Static chars (e.g. ":") never
4472
+ change so they never animate. */
4473
+
4474
+ .rs-ticker {
4475
+ display: inline-flex;
4476
+ font-variant-numeric: tabular-nums;
4477
+ line-height: 1;
4478
+ }
4479
+
4480
+ .rs-ticker-slot {
4481
+ position: relative;
4482
+ display: inline-block;
4483
+ overflow: hidden;
4484
+ height: 1em;
4485
+ line-height: 1;
4486
+ vertical-align: baseline;
4487
+ }
4488
+
4489
+ .rs-ticker-in,
4490
+ .rs-ticker-out {
4491
+ display: inline-block;
4492
+ line-height: 1;
4493
+ }
4494
+
4495
+ .rs-ticker-out {
4496
+ position: absolute;
4497
+ top: 0;
4498
+ left: 0;
4499
+ right: 0;
4500
+ animation: rs-ticker-out 320ms cubic-bezier(0.16, 1, 0.3, 1) both;
4501
+ }
4502
+
4503
+ .rs-ticker-in {
4504
+ animation: rs-ticker-in 320ms cubic-bezier(0.16, 1, 0.3, 1) both;
4505
+ }
4506
+
4507
+ @keyframes rs-ticker-out {
4508
+ from {
4509
+ transform: translateY(0);
4510
+ opacity: 1;
4511
+ }
4512
+ to {
4513
+ transform: translateY(-70%);
4514
+ opacity: 0;
4515
+ }
4516
+ }
4517
+
4518
+ @keyframes rs-ticker-in {
4519
+ from {
4520
+ transform: translateY(70%);
4521
+ opacity: 0;
4522
+ }
4523
+ to {
4524
+ transform: translateY(0);
4525
+ opacity: 1;
4526
+ }
4527
+ }
4528
+
4529
+ @media (prefers-reduced-motion: reduce) {
4530
+ .rs-ticker-in,
4531
+ .rs-ticker-out {
4532
+ animation: none;
4533
+ }
4534
+ .rs-ticker-out {
4535
+ display: none;
4536
+ }
4537
+ }
4538
+
4357
4539
  /* List row — Figma "oauth button" pattern */
4358
4540
 
4359
4541
  .rs-list {
@@ -4531,3 +4713,431 @@
4531
4713
  border: 1px solid var(--rs-border);
4532
4714
  background-color: var(--rs-background);
4533
4715
  }
4716
+
4717
+ /* =============================================================================
4718
+ Fiat On-Ramp (Swapped iframe flow)
4719
+ ============================================================================= */
4720
+
4721
+ /* `.rs-fiat-onramp` is a marker class on the .rs-screen root so the
4722
+ modal-content `:has()` rules below can size correctly. Layout (padding,
4723
+ gap, flex direction) comes from .rs-screen itself, identical to
4724
+ ConnectStep — keeps the top of the page visually unchanged across the
4725
+ payment-method picker → Swapped iframe transition. */
4726
+
4727
+ .rs-fiat-onramp-banner {
4728
+ display: flex;
4729
+ flex-direction: column;
4730
+ gap: 2px;
4731
+ padding: 8px 12px;
4732
+ border-radius: var(--rs-radius-sm);
4733
+ font-size: 12px;
4734
+ line-height: 1.35;
4735
+ border: 1px solid var(--rs-border);
4736
+ }
4737
+
4738
+ .rs-fiat-onramp-banner--info {
4739
+ background: var(--rs-background-secondary);
4740
+ color: var(--rs-foreground);
4741
+ }
4742
+
4743
+ .rs-fiat-onramp-banner--success {
4744
+ background: rgba(34, 197, 94, 0.08);
4745
+ border-color: rgba(34, 197, 94, 0.35);
4746
+ color: var(--rs-foreground);
4747
+ }
4748
+
4749
+ .rs-fiat-onramp-banner--warning {
4750
+ background: rgba(234, 179, 8, 0.08);
4751
+ border-color: rgba(234, 179, 8, 0.4);
4752
+ color: var(--rs-foreground);
4753
+ }
4754
+
4755
+ .rs-fiat-onramp-banner-title {
4756
+ font-weight: 600;
4757
+ }
4758
+
4759
+ .rs-fiat-onramp-banner-detail {
4760
+ color: var(--rs-muted);
4761
+ }
4762
+
4763
+ /* Iframe wrap sized to Swapped's documented dimensions — 400×482 for the
4764
+ fiat on-ramp, 445×585 for Connect (overrides below). Centered horizontally
4765
+ inside the modal so the step body can have header padding. */
4766
+ .rs-fiat-onramp-iframe-wrap {
4767
+ position: relative;
4768
+ width: 100%;
4769
+ max-width: 400px;
4770
+ min-height: 482px;
4771
+ margin: 0 auto;
4772
+ border-radius: var(--rs-radius);
4773
+ overflow: hidden;
4774
+ }
4775
+
4776
+ .rs-fiat-onramp[data-variant="connect"] .rs-fiat-onramp-iframe-wrap {
4777
+ max-width: 445px;
4778
+ min-height: 585px;
4779
+ }
4780
+
4781
+ .rs-fiat-onramp-iframe {
4782
+ display: block;
4783
+ width: 100%;
4784
+ height: 482px;
4785
+ min-height: 482px;
4786
+ border: 0;
4787
+ background: var(--rs-background);
4788
+ }
4789
+
4790
+ .rs-fiat-onramp[data-variant="connect"] .rs-fiat-onramp-iframe {
4791
+ height: 585px;
4792
+ min-height: 585px;
4793
+ }
4794
+
4795
+ .rs-fiat-onramp-loading,
4796
+ .rs-fiat-onramp-error {
4797
+ position: absolute;
4798
+ inset: 0;
4799
+ display: flex;
4800
+ flex-direction: column;
4801
+ align-items: center;
4802
+ justify-content: center;
4803
+ gap: 12px;
4804
+ text-align: center;
4805
+ background: var(--rs-background);
4806
+ color: var(--rs-foreground);
4807
+ padding: 16px;
4808
+ }
4809
+
4810
+ .rs-fiat-onramp-retry {
4811
+ padding: 6px 14px;
4812
+ border: 1px solid var(--rs-border);
4813
+ border-radius: var(--rs-radius-sm);
4814
+ background: var(--rs-background-secondary);
4815
+ color: var(--rs-foreground);
4816
+ font-size: 12px;
4817
+ font-weight: 500;
4818
+ font-family: inherit;
4819
+ cursor: pointer;
4820
+ }
4821
+
4822
+ .rs-fiat-onramp-retry:hover {
4823
+ background: var(--rs-border);
4824
+ }
4825
+
4826
+ /* =============================================================================
4827
+ Exchange picker (Swapped Connect)
4828
+ ============================================================================= */
4829
+
4830
+ .rs-exchange-grid {
4831
+ display: grid;
4832
+ grid-template-columns: repeat(2, minmax(0, 1fr));
4833
+ gap: 8px;
4834
+ }
4835
+
4836
+ .rs-exchange-card {
4837
+ display: flex;
4838
+ min-width: 0;
4839
+ min-height: 104px;
4840
+ flex-direction: column;
4841
+ align-items: center;
4842
+ justify-content: center;
4843
+ gap: 10px;
4844
+ padding: 12px 8px;
4845
+ border: 1px solid var(--rs-background-secondary);
4846
+ border-radius: 8px;
4847
+ background: var(--rs-background-secondary);
4848
+ color: var(--rs-foreground);
4849
+ font-family: inherit;
4850
+ cursor: pointer;
4851
+ transition:
4852
+ background-color 0.15s,
4853
+ border-color 0.15s;
4854
+ }
4855
+
4856
+ .rs-exchange-card:hover:not(:disabled) {
4857
+ background: var(--rs-surface-hover);
4858
+ border-color: var(--rs-surface-hover);
4859
+ }
4860
+
4861
+ .rs-exchange-card:focus-visible {
4862
+ outline: 2px solid var(--rs-border-accent);
4863
+ outline-offset: 2px;
4864
+ }
4865
+
4866
+ .rs-exchange-card-logo {
4867
+ display: inline-flex;
4868
+ align-items: center;
4869
+ justify-content: center;
4870
+ width: 44px;
4871
+ height: 44px;
4872
+ border-radius: 10px;
4873
+ background: var(--rs-surface);
4874
+ color: #71717b;
4875
+ overflow: hidden;
4876
+ }
4877
+
4878
+ .rs-exchange-card-logo img,
4879
+ .rs-exchange-card-logo svg {
4880
+ width: 28px;
4881
+ height: 28px;
4882
+ display: block;
4883
+ object-fit: contain;
4884
+ }
4885
+
4886
+ .rs-exchange-card-name {
4887
+ width: 100%;
4888
+ min-width: 0;
4889
+ font-size: 14px;
4890
+ font-weight: 500;
4891
+ line-height: 1.25;
4892
+ color: var(--rs-foreground);
4893
+ text-align: center;
4894
+ overflow: hidden;
4895
+ text-overflow: ellipsis;
4896
+ white-space: nowrap;
4897
+ }
4898
+
4899
+ .rs-exchange-select-state {
4900
+ min-height: 184px;
4901
+ display: flex;
4902
+ flex-direction: column;
4903
+ align-items: center;
4904
+ justify-content: center;
4905
+ gap: 12px;
4906
+ text-align: center;
4907
+ color: var(--rs-foreground);
4908
+ }
4909
+
4910
+ .rs-exchange-select-state-title {
4911
+ font-size: 14px;
4912
+ font-weight: 600;
4913
+ line-height: 1.35;
4914
+ }
4915
+
4916
+ /* =============================================================================
4917
+ Modal sizing for the Swapped iframe step
4918
+ =============================================================================
4919
+ Modal stays at the default 400px width for the fiat variant (matches
4920
+ Swapped's 400×482 iframe edge-to-edge). Connect needs 445px because its
4921
+ iframe is 445×585. Height grows with the Rhinestone chrome (header
4922
+ icon/title/subtitle + iframe + PoweredBy); cap to viewport so smaller
4923
+ laptops get a scrollable modal-body instead of overflowing the screen. */
4924
+
4925
+ /* Connect's iframe is 445×585 (vs fiat's 400×482). To preserve the same
4926
+ 12px horizontal padding as ConnectStep while still giving Swapped's
4927
+ Connect iframe its documented width, widen the modal by 24px (12 each
4928
+ side) → 469px. Applied from the moment the user enters exchange-connect
4929
+ mode (`data-flow-mode` on rs-modal-body) — not just the iframe step —
4930
+ so the modal width is stable across SetupStep → SwappedIframeStep.
4931
+ Fiat keeps the default 400px modal; its iframe renders at 376px
4932
+ content-width, matching the visual width of ConnectStep's list rows. */
4933
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="exchange-connect"]) {
4934
+ max-width: 469px;
4935
+ }
4936
+
4937
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="fiat-onramp"]),
4938
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="exchange-connect"]) {
4939
+ max-height: calc(100vh - 40px);
4940
+ }
4941
+
4942
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="fiat-onramp"]) .rs-modal-body,
4943
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="exchange-connect"]) .rs-modal-body {
4944
+ /* `overflow-x: hidden` is explicit because a `visible` x-axis with an
4945
+ `auto` y-axis gets promoted to `auto` on both axes, which paints a
4946
+ phantom horizontal scrollbar even when content fits horizontally. */
4947
+ overflow: hidden auto;
4948
+ }
4949
+
4950
+ /* Pre-size the modal-content to the eventual iframe-mounted height for
4951
+ the iframe-phase only:
4952
+ - `[data-step-type="setup"]` — brief pre-flight before SwappedIframeStep mounts
4953
+ - `:has(...) .rs-fiat-onramp` — SwappedIframeStep's iframe phase is in DOM
4954
+ The tracker phase (.rs-swapped-tracker) is naturally shorter and is
4955
+ excluded so the modal shrinks down to its content instead of leaving
4956
+ a tall empty area below the tracker. Applied on modal-content (not
4957
+ modal-body) so the transition on its min-height animates smoothly
4958
+ when the iframe→tracker phase swap fires. */
4959
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="fiat-onramp"][data-step-type="setup"]),
4960
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="fiat-onramp"] .rs-fiat-onramp) {
4961
+ min-height: 691px;
4962
+ }
4963
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="exchange-connect"][data-step-type="setup"]),
4964
+ .rs-modal-content:has(.rs-modal-body[data-flow-mode="exchange-connect"] .rs-fiat-onramp) {
4965
+ min-height: 794px;
4966
+ }
4967
+
4968
+ /* =============================================================================
4969
+ Custom order tracker
4970
+ =============================================================================
4971
+ Shown after the user creates an order with Swapped — replaces the iframe
4972
+ until the deposit-processor reports bridge-complete. */
4973
+ /* Layout lives in rs-screen now — tracker just contributes the entrance
4974
+ animation and a marker class for any future tracker-only tweaks. The
4975
+ icon + title come from the shared BodyHeader so the header position
4976
+ matches ConnectStep and SwappedIframeStep exactly. */
4977
+ .rs-swapped-tracker {
4978
+ animation: rs-swapped-tracker-enter 250ms ease-out;
4979
+ }
4980
+
4981
+ @keyframes rs-swapped-tracker-enter {
4982
+ from {
4983
+ opacity: 0;
4984
+ }
4985
+ to {
4986
+ opacity: 1;
4987
+ }
4988
+ }
4989
+
4990
+ @keyframes rs-tracker-step-complete {
4991
+ 0% {
4992
+ transform: scale(0.72);
4993
+ }
4994
+ 60% {
4995
+ transform: scale(1.08);
4996
+ }
4997
+ 100% {
4998
+ transform: scale(1);
4999
+ }
5000
+ }
5001
+
5002
+ .rs-swapped-tracker-steps {
5003
+ list-style: none;
5004
+ padding: 0;
5005
+ margin: 0;
5006
+ display: flex;
5007
+ flex-direction: column;
5008
+ flex-grow: 1;
5009
+ }
5010
+
5011
+ .rs-swapped-tracker-step {
5012
+ position: relative;
5013
+ display: flex;
5014
+ align-items: center;
5015
+ justify-content: space-between;
5016
+ gap: 12px;
5017
+ padding: 16px 0;
5018
+ }
5019
+
5020
+ /* Dotted vertical connector between adjacent step markers. */
5021
+ .rs-swapped-tracker-step + .rs-swapped-tracker-step::before {
5022
+ content: "";
5023
+ position: absolute;
5024
+ top: -14px;
5025
+ right: 11px;
5026
+ width: 0;
5027
+ height: 28px;
5028
+ border-left: 1.5px dotted #d4d4d8;
5029
+ }
5030
+
5031
+ .rs-swapped-tracker-step-label {
5032
+ font-size: 15px;
5033
+ color: var(--rs-foreground);
5034
+ flex-grow: 1;
5035
+ }
5036
+
5037
+ .rs-swapped-tracker-step-marker {
5038
+ width: 24px;
5039
+ height: 24px;
5040
+ border-radius: 50%;
5041
+ flex-shrink: 0;
5042
+ display: flex;
5043
+ align-items: center;
5044
+ justify-content: center;
5045
+ background: transparent;
5046
+ border: 1.5px solid #d4d4d8;
5047
+ color: transparent;
5048
+ transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
5049
+ }
5050
+
5051
+ .rs-swapped-tracker-step--active .rs-swapped-tracker-step-marker {
5052
+ border-color: #d4d4d8;
5053
+ background: transparent;
5054
+ /* Spinner SVG uses currentColor; base marker class sets color:transparent
5055
+ for the (hidden) ring glyph — re-establish a visible color here so the
5056
+ active-state spinner actually paints. */
5057
+ color: #18181b;
5058
+ }
5059
+
5060
+ .rs-swapped-tracker-step--active .rs-swapped-tracker-step-marker .rs-spinner {
5061
+ width: 14px;
5062
+ height: 14px;
5063
+ }
5064
+
5065
+ /* Satisfying scale-pop when a step ticks complete — the color transition
5066
+ alone is too subtle to register as "that just happened". */
5067
+ .rs-swapped-tracker-step--complete .rs-swapped-tracker-step-marker {
5068
+ animation: rs-tracker-step-complete 320ms cubic-bezier(0.34, 1.56, 0.64, 1);
5069
+ background: #18181b;
5070
+ border-color: #18181b;
5071
+ color: #fff;
5072
+ }
5073
+
5074
+ .rs-swapped-tracker-step--complete .rs-swapped-tracker-step-marker svg {
5075
+ width: 14px;
5076
+ height: 14px;
5077
+ stroke-width: 3;
5078
+ }
5079
+
5080
+ /* Failed step marker — terminal processor failure or cancellation. Red in
5081
+ both themes (the failure color reads on light and dark). */
5082
+ .rs-swapped-tracker-step--failed .rs-swapped-tracker-step-marker {
5083
+ background: #fb2c36;
5084
+ border-color: #fb2c36;
5085
+ color: #fff;
5086
+ }
5087
+
5088
+ .rs-swapped-tracker-step--failed .rs-swapped-tracker-step-marker svg {
5089
+ width: 14px;
5090
+ height: 14px;
5091
+ stroke-width: 3;
5092
+ }
5093
+
5094
+ /* Terminal message block shown below the steps on failure / cancellation. */
5095
+ .rs-swapped-tracker-terminal {
5096
+ display: flex;
5097
+ flex-direction: column;
5098
+ align-items: center;
5099
+ gap: 12px;
5100
+ text-align: center;
5101
+ }
5102
+
5103
+ .rs-swapped-tracker-terminal-message {
5104
+ margin: 0;
5105
+ font-size: 14px;
5106
+ line-height: 1.4;
5107
+ color: var(--rs-foreground-secondary, #71717a);
5108
+ }
5109
+
5110
+ .rs-swapped-tracker-terminal--failed .rs-swapped-tracker-terminal-message {
5111
+ color: #fb2c36;
5112
+ }
5113
+
5114
+ .rs-swapped-tracker-retry {
5115
+ padding: 8px 16px;
5116
+ border: 1px solid var(--rs-border);
5117
+ border-radius: var(--rs-radius-sm);
5118
+ background: var(--rs-background-secondary);
5119
+ color: var(--rs-foreground);
5120
+ font-size: 13px;
5121
+ font-weight: 500;
5122
+ font-family: inherit;
5123
+ cursor: pointer;
5124
+ }
5125
+
5126
+ .rs-swapped-tracker-retry:hover {
5127
+ background: var(--rs-border);
5128
+ }
5129
+
5130
+ .rs-modal[data-theme="dark"] .rs-swapped-tracker-step + .rs-swapped-tracker-step::before {
5131
+ border-left-color: #3f3f46;
5132
+ }
5133
+
5134
+ .rs-modal[data-theme="dark"] .rs-swapped-tracker-step--pending .rs-swapped-tracker-step-marker,
5135
+ .rs-modal[data-theme="dark"] .rs-swapped-tracker-step--active .rs-swapped-tracker-step-marker {
5136
+ border-color: #3f3f46;
5137
+ }
5138
+
5139
+ .rs-modal[data-theme="dark"] .rs-swapped-tracker-step--complete .rs-swapped-tracker-step-marker {
5140
+ background: #fafafa;
5141
+ border-color: #fafafa;
5142
+ color: #18181b;
5143
+ }