@mesub/react 0.0.0-stage → 0.1.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.
package/styles.css ADDED
@@ -0,0 +1,2764 @@
1
+ /*!
2
+ * @mesub/react/styles.css: default theme (v5) for the Mesub widget
3
+ *
4
+ * Targets data attributes only (no class names). Element selectors are used
5
+ * only inside the widget roots (h2, p, a, img, strong, dl, details).
6
+ *
7
+ * Theming: set any --mesub-* property on :root, on a wrapper, or on the
8
+ * widget elements themselves. This file never assigns a --mesub-* property,
9
+ * it only reads them with a fallback, so the merchant's value always wins,
10
+ * whatever the specificity of the merchant's selector.
11
+ *
12
+ * --mesub-accent #cc451d actions, current state, focus ring
13
+ * --mesub-on-accent #ffffff text on accent fills (keep >= 4.5:1)
14
+ * --mesub-bg #ffffff modal surface, list rows
15
+ * --mesub-text #14151a titles; derives muted tones + borders
16
+ * --mesub-font inherit merchant font; e.g. system-ui, sans-serif
17
+ * --mesub-radius 6px buttons (modal = radius + 4px)
18
+ * advanced: --mesub-radius-lg, --mesub-text-soft, --mesub-muted, --mesub-sunk,
19
+ * --mesub-border, --mesub-control-border, --mesub-accent-text, --mesub-focus,
20
+ * --mesub-success, --mesub-success-text, --mesub-danger, --mesub-danger-text,
21
+ * --mesub-warning, --mesub-warning-text,
22
+ * --mesub-shadow, --mesub-backdrop, --mesub-duration
23
+ *
24
+ * Dark: data-mesub-theme="dark" on the element or any ancestor (e.g. <html>).
25
+ * data-mesub-theme="auto" follows prefers-color-scheme (opt-in on purpose:
26
+ * the widget must match the merchant's page, not the visitor's OS).
27
+ *
28
+ * Markup, as the components write it:
29
+ * - busy controls carry aria-busy="true"; [data-mesub-wallet] is a <button>
30
+ * - checkout: [data-mesub-step="plan"|"wallet"|"review"|"approve"|"confirming"|"subscribed"],
31
+ * [data-mesub-merchant] (img + <strong> name), [data-mesub-price] (<strong> + <span>),
32
+ * [data-mesub-summary] (<dl>) > [data-mesub-row] > dt + dd,
33
+ * [data-mesub-network="devnet"] badge, [data-mesub-explorer] link, [data-mesub-done],
34
+ * [data-mesub-cancel]
35
+ * - cancel, resume, close: [data-mesub-step="confirm"|"wallet"|"approve"|"confirming"|"done"]
36
+ * - the list of subscriptions: see the MANAGE section
37
+ */
38
+
39
+ /* ---------------------------------------------------------------- tokens */
40
+
41
+ :is([data-mesub-dialog], [data-mesub-subscribe], [data-mesub-subscribe] ~ [data-mesub-receipt], [data-mesub-subscriptions]) {
42
+ --_accent: var(--mesub-accent, #cc451d);
43
+ --_on-accent: var(--mesub-on-accent, #ffffff);
44
+ --_accent-text: var(--mesub-accent-text, var(--_accent));
45
+ --_accent-hover: color-mix(in srgb, var(--_accent) 90%, #000);
46
+ --_accent-active: color-mix(in srgb, var(--_accent) 82%, #000);
47
+ --_focus: var(--mesub-focus, var(--_accent));
48
+
49
+ --_bg: var(--mesub-bg, #ffffff);
50
+ --_text: var(--mesub-text, #14151a);
51
+ --_text-soft: var(--mesub-text-soft, color-mix(in srgb, var(--_text) 78%, var(--_bg)));
52
+ --_muted: var(--mesub-muted, color-mix(in srgb, var(--_text) 62%, var(--_bg)));
53
+ --_sunk: var(--mesub-sunk, color-mix(in srgb, var(--_text) 5%, var(--_bg)));
54
+ --_border: var(--mesub-border, color-mix(in srgb, var(--_text) 10%, transparent));
55
+ --_divider: color-mix(in srgb, var(--_text) 6%, transparent);
56
+ --_control-border: var(--mesub-control-border, color-mix(in srgb, var(--_text) 47%, var(--_bg)));
57
+
58
+ --_success: var(--mesub-success, #0e9384);
59
+ --_success-text: var(--mesub-success-text, #0b7a6e);
60
+ --_danger: var(--mesub-danger, #a5124a);
61
+ --_danger-text: var(--mesub-danger-text, #8f1040);
62
+ --_warning: var(--mesub-warning, #b54708);
63
+ --_warning-text: var(--mesub-warning-text, #93370d);
64
+
65
+ --_radius: var(--mesub-radius, 6px);
66
+ --_radius-lg: var(--mesub-radius-lg, calc(var(--_radius) + 4px));
67
+ --_shadow: var(--mesub-shadow, 0 1px 2px rgb(20 21 26 / 6%), 0 24px 48px -16px rgb(20 21 26 / 28%));
68
+ --_dur: var(--mesub-duration, 140ms);
69
+ --_ease-enter: cubic-bezier(0.22, 1, 0.36, 1);
70
+
71
+ color-scheme: light;
72
+ }
73
+
74
+ /* Dark: only the base colours change; everything else derives. */
75
+ :is([data-mesub-dialog], [data-mesub-subscribe], [data-mesub-subscribe] ~ [data-mesub-receipt], [data-mesub-subscriptions]):is([data-mesub-theme="dark"], [data-mesub-theme="dark"] *) {
76
+ --_bg: var(--mesub-bg, #16171c);
77
+ --_text: var(--mesub-text, #eceef1);
78
+ --_accent-text: var(--mesub-accent-text, color-mix(in srgb, var(--_accent) 70%, #fff));
79
+ --_success-text: var(--mesub-success-text, #2fb5a3);
80
+ --_danger: var(--mesub-danger, #e0577f);
81
+ --_danger-text: var(--mesub-danger-text, #f28aaa);
82
+ --_warning: var(--mesub-warning, #e8a33d);
83
+ --_warning-text: var(--mesub-warning-text, #f2b24a);
84
+ --_border: var(--mesub-border, color-mix(in srgb, var(--_text) 12%, transparent));
85
+ --_sunk: var(--mesub-sunk, color-mix(in srgb, var(--_text) 7%, var(--_bg)));
86
+ --_shadow: var(--mesub-shadow, 0 0 0 1px rgb(255 255 255 / 4%), 0 24px 64px -16px rgb(0 0 0 / 70%));
87
+ color-scheme: dark;
88
+ }
89
+
90
+ @media (prefers-color-scheme: dark) {
91
+ :is([data-mesub-dialog], [data-mesub-subscribe], [data-mesub-subscribe] ~ [data-mesub-receipt], [data-mesub-subscriptions]):is([data-mesub-theme="auto"], [data-mesub-theme="auto"] *) {
92
+ --_bg: var(--mesub-bg, #16171c);
93
+ --_text: var(--mesub-text, #eceef1);
94
+ --_accent-text: var(--mesub-accent-text, color-mix(in srgb, var(--_accent) 70%, #fff));
95
+ --_success-text: var(--mesub-success-text, #2fb5a3);
96
+ --_danger: var(--mesub-danger, #e0577f);
97
+ --_danger-text: var(--mesub-danger-text, #f28aaa);
98
+ --_warning: var(--mesub-warning, #e8a33d);
99
+ --_warning-text: var(--mesub-warning-text, #f2b24a);
100
+ --_border: var(--mesub-border, color-mix(in srgb, var(--_text) 12%, transparent));
101
+ --_sunk: var(--mesub-sunk, color-mix(in srgb, var(--_text) 7%, var(--_bg)));
102
+ --_shadow: var(--mesub-shadow, 0 0 0 1px rgb(255 255 255 / 4%), 0 24px 64px -16px rgb(0 0 0 / 70%));
103
+ color-scheme: dark;
104
+ }
105
+ }
106
+
107
+ /* ---------------------------------------------------------------- dialog */
108
+
109
+ [data-mesub-dialog] {
110
+ box-sizing: border-box;
111
+ inline-size: min(400px, calc(100vw - 32px));
112
+ max-inline-size: none;
113
+ max-block-size: calc(100dvh - 32px);
114
+ margin: auto;
115
+ padding: 24px;
116
+ overflow: auto;
117
+ border: 1px solid var(--_border);
118
+ border-radius: var(--_radius-lg);
119
+ background: var(--_bg);
120
+ color: var(--_text-soft);
121
+ box-shadow: var(--_shadow);
122
+ font-family: var(--mesub-font, inherit);
123
+ font-size: 14px;
124
+ line-height: 20px;
125
+ font-weight: 400;
126
+ text-align: start;
127
+ }
128
+
129
+ /* display only when open: never override the closed dialog's display:none */
130
+ [data-mesub-dialog][open] {
131
+ display: grid;
132
+ grid-template-columns: minmax(0, 1fr) auto;
133
+ row-gap: 16px;
134
+ column-gap: 16px;
135
+ animation: mesub-enter 240ms var(--_ease-enter);
136
+ }
137
+
138
+ [data-mesub-dialog]::backdrop {
139
+ background: var(--mesub-backdrop, rgb(20 21 26 / 40%));
140
+ animation: mesub-fade 240ms ease-out;
141
+ }
142
+ [data-mesub-dialog]:is([data-mesub-theme="dark"], [data-mesub-theme="dark"] *)::backdrop {
143
+ background: var(--mesub-backdrop, rgb(0 0 0 / 60%));
144
+ }
145
+
146
+ [data-mesub-dialog] *,
147
+ [data-mesub-dialog] *::before,
148
+ [data-mesub-dialog] *::after {
149
+ box-sizing: border-box;
150
+ }
151
+
152
+ /* every child takes a full row */
153
+ [data-mesub-dialog][open] > * {
154
+ grid-column: 1 / -1;
155
+ }
156
+
157
+ [data-mesub-dialog] h2 {
158
+ margin: 0;
159
+ padding-inline-end: 40px; /* room for the close button */
160
+ color: var(--_text);
161
+ font-size: 22px;
162
+ line-height: 28px;
163
+ font-weight: 600;
164
+ letter-spacing: -0.02em;
165
+ }
166
+
167
+ [data-mesub-dialog] p {
168
+ margin: 0;
169
+ }
170
+ [data-mesub-dialog] h2 + p {
171
+ margin-block-start: -8px;
172
+ }
173
+ [data-mesub-dialog] strong {
174
+ color: var(--_text);
175
+ font-weight: 500;
176
+ }
177
+ [data-mesub-dialog] a {
178
+ color: var(--_accent-text);
179
+ text-decoration: underline;
180
+ text-underline-offset: 2px;
181
+ border-radius: 2px;
182
+ }
183
+
184
+ /* --------------------------------------------------------------- buttons */
185
+
186
+ :is([data-mesub-submit], [data-mesub-subscribe]) {
187
+ display: inline-flex;
188
+ align-items: center;
189
+ justify-content: center;
190
+ gap: 8px;
191
+ min-block-size: 44px;
192
+ margin: 0;
193
+ padding: 0 20px;
194
+ border: 1px solid transparent;
195
+ border-radius: var(--_radius);
196
+ background: var(--_accent);
197
+ color: var(--_on-accent);
198
+ font-family: var(--mesub-font, inherit);
199
+ font-size: 14px;
200
+ line-height: 20px;
201
+ font-weight: 500;
202
+ text-decoration: none;
203
+ white-space: nowrap;
204
+ cursor: pointer;
205
+ transition-property: color, background-color, border-color;
206
+ transition-duration: var(--_dur);
207
+ transition-timing-function: ease-out;
208
+ }
209
+ [data-mesub-submit] {
210
+ inline-size: 100%;
211
+ margin-block-start: 8px;
212
+ }
213
+ [data-mesub-submit]:not(:disabled, [aria-busy="true"]):hover {
214
+ background: var(--_accent-hover);
215
+ }
216
+ [data-mesub-submit]:not(:disabled, [aria-busy="true"]):active {
217
+ background: var(--_accent-active);
218
+ }
219
+ [data-mesub-submit]:disabled:not([aria-busy="true"]) {
220
+ background: var(--_sunk);
221
+ color: var(--_muted);
222
+ cursor: not-allowed;
223
+ }
224
+ [data-mesub-submit][aria-busy="true"] {
225
+ cursor: progress;
226
+ }
227
+
228
+ /* quiet text button: Back */
229
+ [data-mesub-back] {
230
+ display: inline-flex;
231
+ align-items: center;
232
+ gap: 6px;
233
+ min-block-size: 36px;
234
+ margin: 0;
235
+ padding: 0 8px;
236
+ border: 0;
237
+ border-radius: var(--_radius);
238
+ background: transparent;
239
+ color: var(--_text-soft);
240
+ font: inherit;
241
+ font-size: 13px;
242
+ font-weight: 500;
243
+ cursor: pointer;
244
+ transition: color var(--_dur) ease-out, background-color var(--_dur) ease-out;
245
+ }
246
+ [data-mesub-back] {
247
+ grid-column: 1 !important;
248
+ justify-self: start;
249
+ margin-inline-start: -8px;
250
+ }
251
+ [data-mesub-back]::before {
252
+ content: "";
253
+ inline-size: 7px;
254
+ block-size: 7px;
255
+ border-inline-start: 1.5px solid currentColor;
256
+ border-block-end: 1.5px solid currentColor;
257
+ transform: rotate(45deg);
258
+ }
259
+
260
+ [data-mesub-back]:hover {
261
+ background: var(--_sunk);
262
+ }
263
+ [data-mesub-back]:disabled {
264
+ color: var(--_muted);
265
+ cursor: default;
266
+ background: transparent;
267
+ }
268
+
269
+ /* close: top right, an icon drawn in CSS when the button is empty */
270
+ [data-mesub-close] {
271
+ position: absolute;
272
+ inset-block-start: 12px;
273
+ inset-inline-end: 12px;
274
+ display: grid;
275
+ place-items: center;
276
+ inline-size: 36px;
277
+ block-size: 36px;
278
+ margin: 0;
279
+ padding: 0;
280
+ border: 0;
281
+ border-radius: var(--_radius);
282
+ background: transparent;
283
+ color: var(--_muted);
284
+ font: inherit;
285
+ font-size: 20px;
286
+ line-height: 1;
287
+ cursor: pointer;
288
+ transition: color var(--_dur) ease-out, background-color var(--_dur) ease-out;
289
+ }
290
+ /* hover tints the cross itself, never a grey square behind it */
291
+ [data-mesub-close]:hover {
292
+ background: transparent;
293
+ color: var(--_accent);
294
+ }
295
+ [data-mesub-close]:empty::before,
296
+ [data-mesub-close]:empty::after {
297
+ content: "";
298
+ grid-area: 1 / 1;
299
+ inline-size: 14px;
300
+ block-size: 1.5px;
301
+ border-radius: 1px;
302
+ background: currentColor;
303
+ transform: rotate(45deg);
304
+ }
305
+ [data-mesub-close]:empty::after {
306
+ transform: rotate(-45deg);
307
+ }
308
+
309
+ /* ---------------------------------------------------------------- wallets */
310
+
311
+ [data-mesub-wallets] {
312
+ display: grid;
313
+ margin: 0;
314
+ padding: 0;
315
+ list-style: none;
316
+ overflow: hidden;
317
+ border: 1px solid var(--_border);
318
+ border-radius: var(--_radius-lg);
319
+ }
320
+ [data-mesub-wallets] > * + * {
321
+ border-block-start: 1px solid var(--_divider);
322
+ }
323
+ [data-mesub-wallets] > li {
324
+ display: contents; /* if items are wrapped in <li>, the button carries the row */
325
+ }
326
+ [data-mesub-wallets] > li + li > [data-mesub-wallet] {
327
+ border-block-start: 1px solid var(--_divider);
328
+ }
329
+
330
+ [data-mesub-wallet] {
331
+ display: flex;
332
+ align-items: center;
333
+ gap: 12px;
334
+ inline-size: 100%;
335
+ min-block-size: 52px;
336
+ margin: 0;
337
+ padding: 0 16px;
338
+ border: 0;
339
+ border-radius: 0;
340
+ background: var(--_bg);
341
+ color: var(--_text);
342
+ font: inherit;
343
+ font-size: 14px;
344
+ font-weight: 500;
345
+ text-align: start;
346
+ cursor: pointer;
347
+ transition: background-color var(--_dur) ease-out, color var(--_dur) ease-out;
348
+ }
349
+ [data-mesub-wallet] img {
350
+ flex: none;
351
+ inline-size: 24px;
352
+ block-size: 24px;
353
+ border-radius: 6px;
354
+ }
355
+ /* trailing chevron */
356
+ [data-mesub-wallet]::after {
357
+ content: "";
358
+ flex: none;
359
+ margin-inline-start: auto;
360
+ inline-size: 7px;
361
+ block-size: 7px;
362
+ border-inline-end: 1.5px solid var(--_muted);
363
+ border-block-start: 1.5px solid var(--_muted);
364
+ transform: rotate(45deg);
365
+ }
366
+ [data-mesub-wallet]:hover:not(:disabled) {
367
+ background: var(--_sunk);
368
+ }
369
+ [data-mesub-wallet]:focus-visible {
370
+ outline-offset: -2px !important;
371
+ border-radius: var(--_radius-lg);
372
+ }
373
+ [data-mesub-wallet]:disabled:not([aria-busy="true"]) {
374
+ color: var(--_muted);
375
+ cursor: default;
376
+ }
377
+ [data-mesub-wallet]:disabled:not([aria-busy="true"]) img {
378
+ opacity: 0.5;
379
+ }
380
+ [data-mesub-wallet][aria-busy="true"] {
381
+ background: var(--_sunk);
382
+ cursor: progress;
383
+ }
384
+ /* busy: the chevron becomes a spinner */
385
+ [data-mesub-wallet][aria-busy="true"]::after {
386
+ inline-size: 12px;
387
+ block-size: 12px;
388
+ border: 2px solid var(--_accent);
389
+ border-inline-end-color: transparent;
390
+ border-radius: 50%;
391
+ transform: none;
392
+ animation: mesub-spin 800ms linear infinite;
393
+ }
394
+
395
+ [data-mesub-no-wallet] {
396
+ margin: 0;
397
+ padding: 16px;
398
+ border-radius: var(--_radius-lg);
399
+ background: var(--_sunk);
400
+ color: var(--_text-soft);
401
+ font-size: 14px;
402
+ line-height: 20px;
403
+ }
404
+
405
+ /* --------------------------------------------------- errors and notices */
406
+
407
+ [data-mesub-dialog] [data-mesub-error] {
408
+ display: flex;
409
+ align-items: flex-start;
410
+ gap: 8px;
411
+ margin: 0;
412
+ color: var(--_danger-text);
413
+ font-family: var(--mesub-font, inherit);
414
+ font-size: 13px;
415
+ line-height: 18px;
416
+ font-weight: 400;
417
+ }
418
+ [data-mesub-dialog] [data-mesub-error]::before {
419
+ content: "!";
420
+ flex: none;
421
+ display: grid;
422
+ place-items: center;
423
+ inline-size: 14px;
424
+ block-size: 14px;
425
+ margin-block-start: 2px;
426
+ border-radius: 50%;
427
+ background: var(--_danger);
428
+ color: var(--_bg);
429
+ font-size: 10px;
430
+ line-height: 1;
431
+ font-weight: 700;
432
+ }
433
+ [data-mesub-error]:empty {
434
+ display: none !important;
435
+ }
436
+
437
+ [data-mesub-notice] {
438
+ display: flex;
439
+ align-items: center;
440
+ gap: 8px;
441
+ margin: 0;
442
+ padding: 8px 12px;
443
+ border-radius: var(--_radius);
444
+ background: var(--_sunk);
445
+ color: var(--_text-soft);
446
+ font-size: 13px;
447
+ line-height: 18px;
448
+ }
449
+ [data-mesub-notice]:empty {
450
+ display: none;
451
+ }
452
+ [data-mesub-notice][aria-busy="true"]::before {
453
+ content: "";
454
+ flex: none;
455
+ inline-size: 12px;
456
+ block-size: 12px;
457
+ border: 2px solid var(--_accent);
458
+ border-inline-end-color: transparent;
459
+ border-radius: 50%;
460
+ animation: mesub-spin 800ms linear infinite;
461
+ }
462
+
463
+ /* ------------------------------------------------- done: cancelled, resumed, closed */
464
+
465
+ [data-mesub-dialog][data-mesub-step="done"][open] {
466
+ justify-items: center;
467
+ text-align: center;
468
+ padding-block: 40px 24px;
469
+ }
470
+ [data-mesub-dialog][data-mesub-step="done"] h2 {
471
+ display: grid;
472
+ justify-items: center;
473
+ gap: 16px;
474
+ padding-inline-end: 0;
475
+ }
476
+ [data-mesub-dialog][data-mesub-step="done"] h2::before {
477
+ content: "";
478
+ inline-size: 40px;
479
+ block-size: 40px;
480
+ border-radius: 50%;
481
+ background:
482
+ linear-gradient(var(--_success-text), var(--_success-text)) 15px 21px / 6px 2px no-repeat,
483
+ linear-gradient(var(--_success-text), var(--_success-text)) 19px 14px / 2px 9px no-repeat,
484
+ color-mix(in srgb, var(--_success) 14%, var(--_bg));
485
+ transform: rotate(45deg);
486
+ }
487
+
488
+ /* ------------------------------------------------------ subscribe button */
489
+
490
+ [data-mesub-subscribe]:is([data-mesub-state="idle"], [data-mesub-state="open"]):not(:disabled):hover {
491
+ background: var(--_accent-hover);
492
+ }
493
+ [data-mesub-subscribe]:is([data-mesub-state="idle"], [data-mesub-state="open"]):not(:disabled):active {
494
+ background: var(--_accent-active);
495
+ }
496
+ [data-mesub-subscribe]:is([data-mesub-state="signing"], [data-mesub-state="confirming"]) {
497
+ cursor: progress;
498
+ }
499
+ [data-mesub-subscribe][data-mesub-state="subscribed"] {
500
+ border-color: color-mix(in srgb, var(--_success) 32%, transparent);
501
+ background: color-mix(in srgb, var(--_success) 10%, var(--_bg));
502
+ color: var(--_success-text);
503
+ cursor: default;
504
+ }
505
+ [data-mesub-subscribe][data-mesub-state="subscribed"]::before {
506
+ content: "";
507
+ inline-size: 10px;
508
+ block-size: 5px;
509
+ margin-block-start: -3px;
510
+ border-inline-start: 2px solid currentColor;
511
+ border-block-end: 2px solid currentColor;
512
+ transform: rotate(-45deg);
513
+ }
514
+
515
+ /* ======================================================= subscribe flow */
516
+
517
+ /* merchant header: logo 40px, name; the plan name is the step's h2 */
518
+ [data-mesub-merchant] {
519
+ display: flex;
520
+ align-items: center;
521
+ gap: 12px;
522
+ margin: 0;
523
+ padding-inline-end: 40px;
524
+ color: var(--_text);
525
+ font-size: 14px;
526
+ line-height: 20px;
527
+ font-weight: 600;
528
+ }
529
+ [data-mesub-merchant] img {
530
+ flex: none;
531
+ inline-size: 40px;
532
+ block-size: 40px;
533
+ border-radius: var(--_radius-lg);
534
+ object-fit: cover;
535
+ }
536
+ [data-mesub-merchant] strong {
537
+ font-weight: 600;
538
+ }
539
+ [data-mesub-merchant] [data-mesub-network] {
540
+ margin-inline-start: auto;
541
+ }
542
+
543
+ [data-mesub-network="devnet"] {
544
+ display: inline-flex;
545
+ align-items: center;
546
+ gap: 6px;
547
+ justify-self: start;
548
+ padding: 2px 8px;
549
+ border-radius: 999px;
550
+ background: color-mix(in srgb, var(--_warning) 12%, var(--_bg));
551
+ color: var(--_warning-text);
552
+ font-size: 12px;
553
+ line-height: 16px;
554
+ font-weight: 500;
555
+ white-space: nowrap;
556
+ }
557
+ [data-mesub-network="devnet"]::before {
558
+ content: "";
559
+ inline-size: 6px;
560
+ block-size: 6px;
561
+ border-radius: 50%;
562
+ background: currentColor;
563
+ }
564
+
565
+ [data-mesub-price] {
566
+ display: grid;
567
+ gap: 2px;
568
+ margin: 0;
569
+ }
570
+ [data-mesub-price] strong {
571
+ color: var(--_text);
572
+ font-size: 40px;
573
+ line-height: 44px;
574
+ font-weight: 600;
575
+ letter-spacing: -0.03em;
576
+ font-variant-numeric: tabular-nums;
577
+ }
578
+ [data-mesub-price] span {
579
+ color: var(--_text-soft);
580
+ font-size: 14px;
581
+ }
582
+
583
+ [data-mesub-summary] {
584
+ display: grid;
585
+ margin: 0;
586
+ border-block: 1px solid var(--_divider);
587
+ }
588
+ [data-mesub-row] {
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: space-between;
592
+ gap: 16px;
593
+ min-block-size: 40px;
594
+ padding-block: 10px;
595
+ font-size: 13px;
596
+ line-height: 18px;
597
+ }
598
+ [data-mesub-row] + [data-mesub-row] {
599
+ border-block-start: 1px solid var(--_divider);
600
+ }
601
+ [data-mesub-row] dt {
602
+ color: var(--_text-soft);
603
+ }
604
+ [data-mesub-row] dd {
605
+ display: inline-flex;
606
+ align-items: center;
607
+ gap: 6px;
608
+ margin: 0;
609
+ color: var(--_text);
610
+ font-weight: 500;
611
+ text-align: end;
612
+ font-variant-numeric: tabular-nums;
613
+ }
614
+ [data-mesub-row] dd img {
615
+ inline-size: 16px;
616
+ block-size: 16px;
617
+ border-radius: 4px;
618
+ }
619
+ [data-mesub-row] dd small {
620
+ color: var(--_muted);
621
+ font-size: 12px;
622
+ font-weight: 400;
623
+ }
624
+
625
+ [data-mesub-done] {
626
+ display: inline-flex;
627
+ align-items: center;
628
+ justify-content: center;
629
+ inline-size: 100%;
630
+ min-block-size: 44px;
631
+ margin: 8px 0 0;
632
+ padding: 0 20px;
633
+ border: 1px solid transparent;
634
+ border-radius: var(--_radius);
635
+ background: var(--_accent);
636
+ color: var(--_on-accent);
637
+ font: inherit;
638
+ font-size: 14px;
639
+ font-weight: 500;
640
+ cursor: pointer;
641
+ transition: background-color var(--_dur) ease-out;
642
+ }
643
+ [data-mesub-done]:hover {
644
+ background: var(--_accent-hover);
645
+ }
646
+
647
+ [data-mesub-cancel] {
648
+ justify-self: center;
649
+ min-block-size: 36px;
650
+ margin: 0;
651
+ padding: 0 12px;
652
+ border: 0;
653
+ border-radius: var(--_radius);
654
+ background: transparent;
655
+ color: var(--_text-soft);
656
+ font: inherit;
657
+ font-size: 13px;
658
+ font-weight: 500;
659
+ cursor: pointer;
660
+ transition: background-color var(--_dur) ease-out, color var(--_dur) ease-out;
661
+ }
662
+ [data-mesub-cancel]:hover {
663
+ background: var(--_sunk);
664
+ color: var(--_text);
665
+ }
666
+
667
+ [data-mesub-explorer] {
668
+ display: inline-flex;
669
+ align-items: center;
670
+ gap: 4px;
671
+ color: var(--_accent-text);
672
+ font-weight: 500;
673
+ }
674
+ [data-mesub-explorer]::after {
675
+ content: "\2197";
676
+ font-size: 12px;
677
+ text-decoration: none;
678
+ }
679
+
680
+ /* subscribed: a calm check before the title */
681
+ [data-mesub-dialog][data-mesub-step="subscribed"] h2 {
682
+ display: grid;
683
+ justify-items: start;
684
+ gap: 16px;
685
+ }
686
+ [data-mesub-dialog][data-mesub-step="subscribed"] h2::before {
687
+ content: "";
688
+ inline-size: 40px;
689
+ block-size: 40px;
690
+ border-radius: 50%;
691
+ background:
692
+ linear-gradient(var(--_success-text), var(--_success-text)) 15px 21px / 6px 2px no-repeat,
693
+ linear-gradient(var(--_success-text), var(--_success-text)) 19px 14px / 2px 9px no-repeat,
694
+ color-mix(in srgb, var(--_success) 14%, var(--_bg));
695
+ transform: rotate(45deg);
696
+ }
697
+
698
+ /* ---------------------------------------------------- spinners and focus */
699
+
700
+ :is([data-mesub-submit][aria-busy="true"], [data-mesub-subscribe]:is([data-mesub-state="signing"], [data-mesub-state="confirming"]))::before {
701
+ content: "";
702
+ flex: none;
703
+ inline-size: 14px;
704
+ block-size: 14px;
705
+ border: 2px solid currentColor;
706
+ border-inline-end-color: transparent;
707
+ border-radius: 50%;
708
+ animation: mesub-spin 800ms linear infinite;
709
+ }
710
+
711
+ [data-mesub-dialog] :focus-visible,
712
+ [data-mesub-subscribe]:focus-visible {
713
+ outline: 2px solid var(--_focus);
714
+ outline-offset: 2px;
715
+ }
716
+
717
+ [data-mesub-dialog]:focus-visible {
718
+ outline: none;
719
+ }
720
+
721
+ /* ============================================================ V2 LAYER
722
+ * Everything above is v1. This layer adds depth, guidance and trust cues:
723
+ * [data-mesub-badge] inside a wallet row ("Last used")
724
+ * figure[data-mesub-message] (what the wallet will show) with a pre
725
+ * [data-mesub-install] links and [data-mesub-reload] button in the no-wallet state
726
+ * [data-mesub-receipt] after the Subscribe button
727
+ */
728
+
729
+ :is([data-mesub-dialog], [data-mesub-subscribe], [data-mesub-subscribe] ~ [data-mesub-receipt], [data-mesub-subscriptions]) {
730
+ --_radius-lg: var(--mesub-radius-lg, calc(var(--_radius) + 8px));
731
+ --_accent-soft: color-mix(in srgb, var(--_accent) 9%, var(--_bg));
732
+ --_accent-ring: color-mix(in srgb, var(--_accent) 24%, transparent);
733
+ --_accent-ink: color-mix(in srgb, var(--_accent-text) 78%, var(--_text));
734
+ --_danger-soft: color-mix(in srgb, var(--_danger) 9%, var(--_bg));
735
+ --_success-soft: color-mix(in srgb, var(--_success) 12%, var(--_bg));
736
+ --_warning-soft: color-mix(in srgb, var(--_warning) 10%, var(--_bg));
737
+ }
738
+
739
+ /* ------------------------------------------------------------ v2 dialog */
740
+
741
+ [data-mesub-dialog] {
742
+ inline-size: min(420px, calc(100vw - 32px));
743
+ padding: 28px;
744
+ }
745
+ [data-mesub-dialog][open] {
746
+ row-gap: 20px;
747
+ }
748
+ [data-mesub-dialog]::backdrop {
749
+ -webkit-backdrop-filter: blur(3px);
750
+ backdrop-filter: blur(3px);
751
+ }
752
+ [data-mesub-dialog] h2 + p {
753
+ margin-block-start: -12px;
754
+ }
755
+
756
+ [data-mesub-dialog]:is([data-mesub-step="wallet"], [data-mesub-step="confirming"]) { --_s1: var(--_accent); --_s2: var(--_accent); --_s3: var(--_accent); }
757
+ [data-mesub-dialog][data-mesub-step="subscribed"] { --_s1: var(--_success); --_s2: var(--_success); --_s3: var(--_success); }
758
+ [data-mesub-dialog][data-mesub-step="done"][open]::before { display: none; }
759
+
760
+ [data-mesub-close] {
761
+ inset-block-start: 26px;
762
+ inset-inline-end: 20px;
763
+ }
764
+
765
+ /* merchant context on every step */
766
+ [data-mesub-merchant] {
767
+ padding-block-end: 20px;
768
+ border-block-end: 1px solid var(--_divider);
769
+ }
770
+
771
+ [data-mesub-merchant] ~ h2 {
772
+ padding-inline-end: 0;
773
+ }
774
+
775
+ /* ---------------------------------------------------------- v2 wallets */
776
+
777
+ [data-mesub-wallets] {
778
+ gap: 8px;
779
+ border: 0;
780
+ border-radius: 0;
781
+ overflow: visible;
782
+ }
783
+ [data-mesub-wallets] > * + * {
784
+ border-block-start: 0;
785
+ }
786
+ /* each row is its own box now: the divider of the joined list becomes its top edge */
787
+ [data-mesub-wallets] > li + li > [data-mesub-wallet] {
788
+ border-block-start: 1px solid var(--_border);
789
+ }
790
+ [data-mesub-wallets] [data-mesub-wallet] {
791
+ min-block-size: 60px;
792
+ padding: 0 16px 0 10px;
793
+ border: 1px solid var(--_border);
794
+ border-radius: var(--_radius-lg);
795
+ transition: border-color var(--_dur) ease-out, background-color var(--_dur) ease-out;
796
+ }
797
+ [data-mesub-wallet] img {
798
+ box-sizing: content-box;
799
+ padding: 6px;
800
+ background: var(--_sunk);
801
+ border-radius: var(--_radius);
802
+ }
803
+ [data-mesub-wallets] [data-mesub-wallet]:hover:not(:disabled) {
804
+ border-color: var(--_accent);
805
+ background: var(--_bg);
806
+ }
807
+ [data-mesub-wallets] [data-mesub-wallet][aria-busy="true"] {
808
+ border-color: var(--_accent);
809
+ background: var(--_accent-soft);
810
+ box-shadow: 0 0 0 3px var(--_accent-ring);
811
+ }
812
+ [data-mesub-wallet]:focus-visible {
813
+ outline-offset: 2px !important;
814
+ }
815
+ [data-mesub-badge] {
816
+ margin-inline-start: auto;
817
+ padding: 2px 8px;
818
+ border-radius: 999px;
819
+ background: var(--_accent-soft);
820
+ color: var(--_accent-ink);
821
+ font-size: 12px;
822
+ line-height: 16px;
823
+ font-weight: 500;
824
+ }
825
+ [data-mesub-wallet]:has([data-mesub-badge])::after {
826
+ margin-inline-start: 4px;
827
+ }
828
+
829
+ /* what the wallet will show: the terms, on the review */
830
+ [data-mesub-message] {
831
+ display: grid;
832
+ gap: 8px;
833
+ margin: 0;
834
+ padding: 14px 16px;
835
+ border-radius: var(--_radius-lg);
836
+ background: var(--_sunk);
837
+ }
838
+ [data-mesub-message] figcaption {
839
+ color: var(--_muted);
840
+ font-size: 12px;
841
+ line-height: 16px;
842
+ font-weight: 500;
843
+ }
844
+ /* Every box property is set: a host page's own `pre` rule (a dark code block,
845
+ say) would otherwise show through and hide the text. */
846
+ [data-mesub-message] pre {
847
+ margin: 0;
848
+ padding: 0;
849
+ border: 0;
850
+ border-radius: 0;
851
+ background: transparent;
852
+ box-shadow: none;
853
+ word-break: normal;
854
+ color: var(--_text);
855
+ font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
856
+ font-size: 12px;
857
+ line-height: 18px;
858
+ white-space: pre-wrap;
859
+ }
860
+ [data-mesub-message] p {
861
+ position: relative;
862
+ padding-inline-start: 18px;
863
+ color: var(--_success-text);
864
+ font-size: 12px;
865
+ line-height: 16px;
866
+ font-weight: 500;
867
+ }
868
+ [data-mesub-message] p::before {
869
+ content: "";
870
+ position: absolute;
871
+ inset-inline-start: 2px;
872
+ inset-block-start: 3px;
873
+ inline-size: 8px;
874
+ block-size: 4px;
875
+ border-inline-start: 1.5px solid currentColor;
876
+ border-block-end: 1.5px solid currentColor;
877
+ transform: rotate(-45deg);
878
+ }
879
+
880
+ /* no wallet: install links as rows, then a reload */
881
+ [data-mesub-no-wallet] {
882
+ display: grid;
883
+ gap: 8px;
884
+ padding: 0;
885
+ background: transparent;
886
+ }
887
+
888
+ [data-mesub-install] {
889
+ display: flex;
890
+ align-items: center;
891
+ gap: 12px;
892
+ min-block-size: 60px;
893
+ padding: 0 16px 0 10px;
894
+ border: 1px solid var(--_border);
895
+ border-radius: var(--_radius-lg);
896
+ color: var(--_text) !important;
897
+ font-weight: 500;
898
+ text-decoration: none !important;
899
+ transition: border-color var(--_dur) ease-out;
900
+ }
901
+ [data-mesub-install]:hover {
902
+ border-color: var(--_accent);
903
+ }
904
+ [data-mesub-install] img {
905
+ box-sizing: content-box;
906
+ inline-size: 24px;
907
+ block-size: 24px;
908
+ padding: 6px;
909
+ border-radius: var(--_radius);
910
+ background: var(--_sunk);
911
+ }
912
+ [data-mesub-install] span {
913
+ margin-inline-start: auto;
914
+ color: var(--_accent-text);
915
+ font-size: 13px;
916
+ }
917
+ [data-mesub-install] span::after {
918
+ content: " \2197";
919
+ }
920
+ [data-mesub-reload] {
921
+ display: inline-flex;
922
+ align-items: center;
923
+ justify-content: center;
924
+ inline-size: 100%;
925
+ min-block-size: 44px;
926
+ margin: 0;
927
+ padding: 0 20px;
928
+ border: 1px solid var(--_control-border);
929
+ border-radius: var(--_radius);
930
+ background: var(--_bg);
931
+ color: var(--_text);
932
+ font: inherit;
933
+ font-size: 14px;
934
+ font-weight: 500;
935
+ cursor: pointer;
936
+ transition: border-color var(--_dur) ease-out, background-color var(--_dur) ease-out;
937
+ }
938
+ [data-mesub-reload]:hover {
939
+ background: var(--_sunk);
940
+ }
941
+
942
+ /* ----------------------------------------------------------- v2 errors */
943
+
944
+ [data-mesub-dialog] [data-mesub-error] {
945
+ display: block;
946
+ position: relative;
947
+ padding-inline-start: 22px;
948
+ }
949
+ [data-mesub-dialog] [data-mesub-error]::before {
950
+ position: absolute;
951
+ inset-inline-start: 0;
952
+ inset-block-start: 2px;
953
+ margin: 0;
954
+ }
955
+ /* a step-level error is a callout */
956
+ [data-mesub-dialog] > [data-mesub-error] {
957
+ padding: 10px 12px 10px 34px;
958
+ border: 1px solid color-mix(in srgb, var(--_danger) 22%, transparent);
959
+ border-radius: var(--_radius);
960
+ background: var(--_danger-soft);
961
+ }
962
+ [data-mesub-dialog] > [data-mesub-error]::before {
963
+ inset-inline-start: 12px;
964
+ inset-block-start: 12px;
965
+ }
966
+ [data-mesub-error] strong {
967
+ color: inherit;
968
+ font-weight: 600;
969
+ }
970
+ [data-mesub-error] code {
971
+ padding: 1px 5px;
972
+ border-radius: 4px;
973
+ background: color-mix(in srgb, currentColor 12%, transparent);
974
+ font-family: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
975
+ font-size: 12px;
976
+ white-space: nowrap;
977
+ }
978
+
979
+ /* ------------------------------------------------------- v2 review step */
980
+
981
+ [data-mesub-dialog]:is([data-mesub-step="plan"], [data-mesub-step="review"]) h2 {
982
+ font-size: 14px;
983
+ line-height: 20px;
984
+ font-weight: 500;
985
+ letter-spacing: 0;
986
+ color: var(--_text-soft);
987
+ }
988
+ [data-mesub-dialog]:is([data-mesub-step="plan"], [data-mesub-step="review"]) h2 + [data-mesub-price] {
989
+ margin-block-start: -18px;
990
+ }
991
+ [data-mesub-price] {
992
+ display: flex;
993
+ flex-wrap: wrap;
994
+ align-items: baseline;
995
+ gap: 4px 10px;
996
+ }
997
+ [data-mesub-price] strong {
998
+ font-size: 48px;
999
+ line-height: 52px;
1000
+ letter-spacing: -0.035em;
1001
+ }
1002
+ [data-mesub-price] span {
1003
+ padding: 2px 10px;
1004
+ border-radius: 999px;
1005
+ background: var(--_sunk);
1006
+ color: var(--_text);
1007
+ font-size: 13px;
1008
+ line-height: 18px;
1009
+ font-weight: 500;
1010
+ }
1011
+ [data-mesub-summary] {
1012
+ padding: 4px 16px;
1013
+ border: 0;
1014
+ border-radius: var(--_radius-lg);
1015
+ background: var(--_sunk);
1016
+ }
1017
+ [data-mesub-row] + [data-mesub-row] {
1018
+ border-block-start-color: color-mix(in srgb, var(--_text) 8%, transparent);
1019
+ }
1020
+
1021
+ [data-mesub-cancel] {
1022
+ margin-block-start: -12px;
1023
+ }
1024
+
1025
+ /* ------------------------------------------------ v2 success moments */
1026
+
1027
+ [data-mesub-dialog]:is([data-mesub-step="subscribed"], [data-mesub-step="done"]) h2::before {
1028
+ inline-size: 48px;
1029
+ block-size: 48px;
1030
+ background:
1031
+ linear-gradient(var(--_bg), var(--_bg)) 18px 25px / 8px 2.5px no-repeat,
1032
+ linear-gradient(var(--_bg), var(--_bg)) 23.5px 15px / 2.5px 12.5px no-repeat,
1033
+ var(--_success);
1034
+ box-shadow: 0 0 0 6px var(--_success-soft);
1035
+ animation: mesub-pop 420ms var(--_ease-enter) both;
1036
+ }
1037
+ [data-mesub-dialog][data-mesub-step="subscribed"][open] {
1038
+ justify-items: stretch;
1039
+ }
1040
+ [data-mesub-dialog][data-mesub-step="subscribed"] h2 {
1041
+ padding-block-start: 6px;
1042
+ }
1043
+
1044
+ /* -------------------------------------------- v2 subscribe button */
1045
+
1046
+ [data-mesub-subscribe] {
1047
+ position: relative;
1048
+ overflow: hidden;
1049
+ min-block-size: 48px;
1050
+ padding: 0 22px;
1051
+ }
1052
+ /* progress hairline along the bottom edge: 1/3 signing, 2/3 confirming, full when subscribed */
1053
+ [data-mesub-subscribe]::after {
1054
+ content: "";
1055
+ position: absolute;
1056
+ inset: auto 0 0;
1057
+ block-size: 3px;
1058
+ background: currentColor;
1059
+ opacity: 0.55;
1060
+ transform: scaleX(0);
1061
+ transform-origin: left;
1062
+ transition: transform 600ms var(--_ease-enter);
1063
+ }
1064
+ [data-mesub-subscribe][data-mesub-state="signing"]::after { transform: scaleX(0.34); }
1065
+ [data-mesub-subscribe][data-mesub-state="confirming"]::after { transform: scaleX(0.72); }
1066
+ [data-mesub-subscribe][data-mesub-state="subscribed"]::after { transform: scaleX(1); opacity: 0.35; }
1067
+
1068
+ [data-mesub-subscribe] ~ [data-mesub-receipt] {
1069
+ display: block;
1070
+ margin-block-start: 8px;
1071
+ color: var(--_muted);
1072
+ font-family: var(--mesub-font, inherit);
1073
+ font-size: 12px;
1074
+ line-height: 16px;
1075
+ }
1076
+ [data-mesub-subscribe] ~ [data-mesub-receipt] {
1077
+ color: var(--_text-soft);
1078
+ }
1079
+ [data-mesub-subscribe] ~ [data-mesub-receipt] a {
1080
+ color: var(--_accent-text);
1081
+ text-underline-offset: 2px;
1082
+ }
1083
+
1084
+ @keyframes mesub-shake {
1085
+ 20% { transform: translateX(-4px); }
1086
+ 40% { transform: translateX(4px); }
1087
+ 60% { transform: translateX(-2px); }
1088
+ 80% { transform: translateX(2px); }
1089
+ }
1090
+ @keyframes mesub-pop { from { transform: rotate(45deg) scale(0.6); opacity: 0; } }
1091
+
1092
+ /* ============================================================ V4 LAYER
1093
+ * Centred, icon-led screens; Mesub brand in the top bar; one smooth progress line.
1094
+ * [data-mesub-brand]: top bar, the Mesub mark (an inline <svg fill="currentColor">) + "mesub.io"
1095
+ * [data-mesub-dialog] > [data-mesub-back]:empty: the icon back button, top left
1096
+ * [data-mesub-hero="wait"|"error"|"pending"|"check"|"empty"] (aria-hidden),
1097
+ * "wait"/"error"/"pending" wrap the wallet or merchant <img>
1098
+ * [data-mesub-funds="safe"|"pending"]: a quiet line, "Nothing was charged."
1099
+ */
1100
+
1101
+ [data-mesub-dialog] {
1102
+ inline-size: min(380px, calc(100vw - 32px));
1103
+ padding: 14px 24px 24px;
1104
+ --_radius-lg: var(--mesub-radius-lg, calc(var(--_radius) + 10px));
1105
+ }
1106
+ [data-mesub-dialog][open] {
1107
+ row-gap: 16px;
1108
+ }
1109
+ [data-mesub-dialog] h2 {
1110
+ padding-inline-end: 0;
1111
+ text-align: center;
1112
+ font-size: 20px;
1113
+ line-height: 26px;
1114
+ }
1115
+ [data-mesub-dialog] h2 + p {
1116
+ margin-block-start: -10px;
1117
+ text-align: center;
1118
+ }
1119
+
1120
+ /* one continuous progress line across the whole journey, on the very top edge:
1121
+ the dialog has no top border, so nothing shows above the line */
1122
+ [data-mesub-dialog][open] {
1123
+ border-block-start-width: 0;
1124
+ }
1125
+ [data-mesub-dialog][open]::before {
1126
+ display: block;
1127
+ content: "";
1128
+ position: absolute;
1129
+ inset: 0 0 auto;
1130
+ block-size: 4px;
1131
+ background:
1132
+ linear-gradient(var(--_bar, var(--_accent)) 0 0) 0 0 / calc(var(--_progress, 0) * 100%) 100% no-repeat,
1133
+ var(--_divider);
1134
+ transition: background-size 520ms var(--_ease-enter);
1135
+ }
1136
+ [data-mesub-dialog]:is([data-mesub-step="plan"], [data-mesub-step="confirm"]) { --_progress: 0.2; }
1137
+ [data-mesub-dialog][data-mesub-step="wallet"] { --_progress: 0.4; }
1138
+ [data-mesub-dialog][data-mesub-step="review"] { --_progress: 0.58; }
1139
+ [data-mesub-dialog][data-mesub-step="approve"] { --_progress: 0.72; }
1140
+ [data-mesub-dialog][data-mesub-step="confirming"] { --_progress: 0.86; }
1141
+ [data-mesub-dialog]:is([data-mesub-step="subscribed"], [data-mesub-step="done"]) { --_progress: 1; --_bar: var(--_success); }
1142
+ [data-mesub-dialog][data-mesub-step="done"][open]::before { display: block; }
1143
+
1144
+ /* top bar: back · Mesub · close */
1145
+ [data-mesub-brand] {
1146
+ display: flex;
1147
+ align-items: center;
1148
+ justify-content: center;
1149
+ gap: 6px;
1150
+ min-block-size: 36px;
1151
+ margin: 0;
1152
+ color: var(--_text);
1153
+ font-size: 13px;
1154
+ line-height: 16px;
1155
+ font-weight: 600;
1156
+ letter-spacing: -0.01em;
1157
+ }
1158
+ [data-mesub-brand] :is(img, svg) {
1159
+ inline-size: auto;
1160
+ block-size: 12px;
1161
+ flex: none;
1162
+ }
1163
+ [data-mesub-close] {
1164
+ inset-block-start: 14px;
1165
+ inset-inline-end: 14px;
1166
+ }
1167
+ /* Out of the grid: placed in it, an absolute child is positioned against the
1168
+ content box, which put the close 28px in from the corner. */
1169
+ [data-mesub-dialog][open] > [data-mesub-close] {
1170
+ grid-column: auto;
1171
+ grid-row: auto;
1172
+ }
1173
+ [data-mesub-dialog] > [data-mesub-back]:empty {
1174
+ position: absolute;
1175
+ inset-block-start: 14px;
1176
+ inset-inline-start: 14px;
1177
+ grid-column: auto !important;
1178
+ display: grid;
1179
+ place-items: center;
1180
+ inline-size: 36px;
1181
+ block-size: 36px;
1182
+ margin: 0;
1183
+ padding: 0;
1184
+ color: var(--_muted);
1185
+ }
1186
+ [data-mesub-dialog] > [data-mesub-back]:empty::before {
1187
+ margin-inline-start: 3px;
1188
+ inline-size: 8px;
1189
+ block-size: 8px;
1190
+ }
1191
+ [data-mesub-dialog] > [data-mesub-back]:empty:hover {
1192
+ color: var(--_text);
1193
+ }
1194
+ /* a text back/cancel under the primary button */
1195
+ [data-mesub-dialog] > [data-mesub-back]:not(:empty) {
1196
+ grid-column: 1 / -1 !important;
1197
+ justify-self: center;
1198
+ margin: -8px 0 0;
1199
+ }
1200
+ [data-mesub-dialog] > [data-mesub-back]:not(:empty)::before {
1201
+ display: none;
1202
+ }
1203
+ [data-mesub-cancel] {
1204
+ margin-block-start: -8px;
1205
+ }
1206
+
1207
+ /* merchant: centred logo + name */
1208
+ [data-mesub-merchant] {
1209
+ flex-direction: column;
1210
+ justify-content: center;
1211
+ gap: 8px;
1212
+ padding: 4px 0 0;
1213
+ border: 0;
1214
+ color: var(--_text-soft);
1215
+ font-size: 13px;
1216
+ line-height: 18px;
1217
+ font-weight: 500;
1218
+ }
1219
+ [data-mesub-merchant] img {
1220
+ inline-size: 56px;
1221
+ block-size: 56px;
1222
+ border-radius: 16px;
1223
+ box-shadow: 0 0 0 1px var(--_border), 0 8px 20px -10px rgb(20 21 26 / 35%);
1224
+ }
1225
+ [data-mesub-merchant] strong {
1226
+ font-weight: 500;
1227
+ }
1228
+ [data-mesub-merchant] [data-mesub-network] {
1229
+ margin: 0;
1230
+ }
1231
+ [data-mesub-merchant] + h2 {
1232
+ margin-block-start: -6px;
1233
+ }
1234
+
1235
+ /* ------------------------------------------------------------- heroes */
1236
+
1237
+ [data-mesub-hero] {
1238
+ position: relative;
1239
+ justify-self: center;
1240
+ display: grid;
1241
+ place-items: center;
1242
+ inline-size: 72px;
1243
+ block-size: 72px;
1244
+ margin-block-start: 4px;
1245
+ }
1246
+ [data-mesub-hero] img {
1247
+ inline-size: 56px;
1248
+ block-size: 56px;
1249
+ border-radius: 16px;
1250
+ box-shadow: 0 0 0 1px var(--_border);
1251
+ }
1252
+ [data-mesub-hero]:is([data-mesub-hero="wait"], [data-mesub-hero="error"], [data-mesub-hero="pending"]) img {
1253
+ inline-size: 44px;
1254
+ block-size: 44px;
1255
+ border-radius: 12px;
1256
+ box-shadow: none;
1257
+ }
1258
+ [data-mesub-hero]:is([data-mesub-hero="wait"], [data-mesub-hero="error"], [data-mesub-hero="pending"])::before {
1259
+ content: "";
1260
+ position: absolute;
1261
+ inset: 0;
1262
+ box-sizing: border-box;
1263
+ border: 3px solid var(--_divider);
1264
+ border-radius: 50%;
1265
+ }
1266
+ [data-mesub-hero="wait"]::before {
1267
+ border-block-start-color: var(--_accent) !important;
1268
+ border-inline-end-color: var(--_accent) !important;
1269
+ animation: mesub-spin 1000ms linear infinite;
1270
+ }
1271
+ [data-mesub-hero="error"]::before {
1272
+ border-color: var(--_danger);
1273
+ }
1274
+ [data-mesub-hero="pending"]::before {
1275
+ border-color: var(--_warning);
1276
+ border-block-end-color: var(--_divider);
1277
+ animation: mesub-spin 2400ms linear infinite;
1278
+ }
1279
+ [data-mesub-hero="error"]::after {
1280
+ content: "!";
1281
+ position: absolute;
1282
+ inset-block-end: 2px;
1283
+ inset-inline-end: 2px;
1284
+ display: grid;
1285
+ place-items: center;
1286
+ inline-size: 20px;
1287
+ block-size: 20px;
1288
+ border-radius: 50%;
1289
+ background: var(--_danger);
1290
+ color: var(--_bg);
1291
+ box-shadow: 0 0 0 3px var(--_bg);
1292
+ font-size: 12px;
1293
+ line-height: 1;
1294
+ font-weight: 700;
1295
+ }
1296
+ [data-mesub-hero="check"]::before {
1297
+ content: "";
1298
+ inline-size: 56px;
1299
+ block-size: 56px;
1300
+ border-radius: 50%;
1301
+ background:
1302
+ linear-gradient(var(--_bg), var(--_bg)) 21px 29px / 9px 3px no-repeat,
1303
+ linear-gradient(var(--_bg), var(--_bg)) 27px 17.5px / 3px 14.5px no-repeat,
1304
+ var(--_success);
1305
+ box-shadow: 0 0 0 8px var(--_success-soft);
1306
+ transform: rotate(45deg);
1307
+ animation: mesub-pop 420ms var(--_ease-enter) both;
1308
+ }
1309
+
1310
+ [data-mesub-hero="empty"]::before {
1311
+ content: "";
1312
+ inline-size: 56px;
1313
+ block-size: 56px;
1314
+ border-radius: 16px;
1315
+ background:
1316
+ linear-gradient(var(--_muted), var(--_muted)) 34px 25px / 6px 6px no-repeat,
1317
+ linear-gradient(var(--_sunk), var(--_sunk)) 17px 19px / 22px 18px no-repeat,
1318
+ linear-gradient(var(--_muted), var(--_muted)) 15px 17px / 26px 22px no-repeat,
1319
+ var(--_sunk);
1320
+ }
1321
+ /* subscribed / done: the hero replaces the inline check */
1322
+ [data-mesub-dialog]:is([data-mesub-step="subscribed"], [data-mesub-step="done"]) h2 {
1323
+ display: block;
1324
+ padding: 0;
1325
+ }
1326
+ [data-mesub-dialog]:is([data-mesub-step="subscribed"], [data-mesub-step="done"]) h2::before {
1327
+ content: none;
1328
+ }
1329
+ [data-mesub-dialog][data-mesub-step="done"][open] {
1330
+ padding-block: 14px 28px;
1331
+ }
1332
+
1333
+ /* under a hero, the alert line is plain centred text */
1334
+ [data-mesub-dialog]:has([data-mesub-hero]) > [data-mesub-error] {
1335
+ margin-block-start: -10px;
1336
+ padding: 0;
1337
+ border: 0;
1338
+ background: none;
1339
+ color: var(--_text-soft);
1340
+ font-size: 14px;
1341
+ line-height: 20px;
1342
+ text-align: center;
1343
+ }
1344
+ [data-mesub-dialog]:has([data-mesub-hero]) > [data-mesub-error]::before {
1345
+ display: none;
1346
+ }
1347
+ [data-mesub-dialog] > [data-mesub-explorer] {
1348
+ justify-self: center;
1349
+ font-size: 13px;
1350
+ }
1351
+
1352
+ /* money status: a quiet line, not a chip */
1353
+ [data-mesub-funds] {
1354
+ position: relative;
1355
+ justify-self: center;
1356
+ margin: -6px 0 0;
1357
+ padding-inline-start: 18px;
1358
+ color: var(--_success-text);
1359
+ font-size: 13px;
1360
+ line-height: 18px;
1361
+ font-weight: 500;
1362
+ }
1363
+ [data-mesub-funds]::before {
1364
+ content: "";
1365
+ position: absolute;
1366
+ inset-inline-start: 2px;
1367
+ inset-block-start: 4px;
1368
+ inline-size: 9px;
1369
+ block-size: 5px;
1370
+ border-inline-start: 1.5px solid currentColor;
1371
+ border-block-end: 1.5px solid currentColor;
1372
+ transform: rotate(-45deg);
1373
+ }
1374
+ [data-mesub-funds="pending"] {
1375
+ color: var(--_warning-text);
1376
+ }
1377
+ [data-mesub-funds="pending"]::before {
1378
+ inset-block-start: 6px;
1379
+ inline-size: 6px;
1380
+ block-size: 6px;
1381
+ border: 0;
1382
+ border-radius: 50%;
1383
+ background: currentColor;
1384
+ transform: none;
1385
+ }
1386
+
1387
+ /* ------------------------------------------------------------ buttons */
1388
+
1389
+ :is([data-mesub-submit], [data-mesub-done]) {
1390
+ min-block-size: 48px;
1391
+ border-radius: var(--_radius-lg);
1392
+ }
1393
+
1394
+ [data-mesub-notice] {
1395
+ justify-content: center;
1396
+ padding: 0;
1397
+ background: none;
1398
+ }
1399
+
1400
+ /* ------------------------------------------------------------ wallets */
1401
+
1402
+ [data-mesub-wallets] {
1403
+ gap: 8px;
1404
+ }
1405
+ [data-mesub-wallets] [data-mesub-wallet] {
1406
+ min-block-size: 56px;
1407
+ padding: 0 14px;
1408
+ gap: 12px;
1409
+ border: 1px solid transparent;
1410
+ border-radius: var(--_radius-lg);
1411
+ background: var(--_sunk);
1412
+ font-size: 15px;
1413
+ }
1414
+ [data-mesub-wallets] [data-mesub-wallet]:hover:not(:disabled) {
1415
+ border-color: var(--_accent);
1416
+ background: var(--_sunk);
1417
+ }
1418
+ [data-mesub-wallet] img {
1419
+ inline-size: 28px;
1420
+ block-size: 28px;
1421
+ padding: 0;
1422
+ background: none;
1423
+ border-radius: 8px;
1424
+ }
1425
+ [data-mesub-wallet]::after {
1426
+ display: none;
1427
+ }
1428
+ [data-mesub-badge] {
1429
+ background: var(--_bg);
1430
+ color: var(--_text-soft);
1431
+ box-shadow: inset 0 0 0 1px var(--_border);
1432
+ }
1433
+
1434
+ [data-mesub-no-wallet] {
1435
+ margin-block-start: 4px;
1436
+ }
1437
+ [data-mesub-install] {
1438
+ min-block-size: 56px;
1439
+ padding: 0 14px;
1440
+ border-color: transparent;
1441
+ background: var(--_sunk);
1442
+ }
1443
+ [data-mesub-install] img {
1444
+ inline-size: 28px;
1445
+ block-size: 28px;
1446
+ padding: 0;
1447
+ background: none;
1448
+ border-radius: 8px;
1449
+ }
1450
+ [data-mesub-reload] {
1451
+ min-block-size: 48px;
1452
+ border-radius: var(--_radius-lg);
1453
+ }
1454
+
1455
+ /* ------------------------------------------------------------- review */
1456
+
1457
+ [data-mesub-dialog]:is([data-mesub-step="plan"], [data-mesub-step="review"]) h2 {
1458
+ color: var(--_text);
1459
+ font-size: 20px;
1460
+ line-height: 26px;
1461
+ font-weight: 600;
1462
+ letter-spacing: -0.02em;
1463
+ }
1464
+ [data-mesub-dialog]:is([data-mesub-step="plan"], [data-mesub-step="review"]) h2 + [data-mesub-price] {
1465
+ margin-block-start: -14px;
1466
+ }
1467
+ [data-mesub-price] {
1468
+ display: grid;
1469
+ justify-items: center;
1470
+ gap: 0;
1471
+ }
1472
+ [data-mesub-price] strong {
1473
+ font-size: 40px;
1474
+ line-height: 46px;
1475
+ }
1476
+ [data-mesub-price] span {
1477
+ padding: 0;
1478
+ background: none;
1479
+ color: var(--_text-soft);
1480
+ font-size: 14px;
1481
+ font-weight: 400;
1482
+ }
1483
+ [data-mesub-summary] {
1484
+ padding: 2px 16px;
1485
+ }
1486
+ [data-mesub-summary] + p {
1487
+ margin-block-start: -6px;
1488
+ color: var(--_muted);
1489
+ font-size: 12px;
1490
+ line-height: 16px;
1491
+ text-align: center;
1492
+ }
1493
+
1494
+ /* ============================================================ V5 LAYER
1495
+ * Cleaner surfaces and a motion system. Every decorative animation sits inside
1496
+ * prefers-reduced-motion: no-preference, so reduced-motion users get none of it
1497
+ * (spinners keep the v1 slow-down).
1498
+ *
1499
+ * Motion tokens
1500
+ * enter 380ms cubic-bezier(0.22, 1, 0.36, 1) modal (scale + blur in)
1501
+ * rise 420ms same curve, 45ms stagger each step's content, on mount
1502
+ * spring cubic-bezier(0.34, 1.56, 0.64, 1) badges, check pop
1503
+ * press 120ms scale(0.98) buttons and rows
1504
+ * progress 600ms spring-ish fill top line
1505
+ * Extra markup: details[data-mesub-terms] > summary + figure[data-mesub-message] on the
1506
+ * review, closed by default: the terms the wallet is about to show.
1507
+ */
1508
+
1509
+ /* ------------------------------------------------------------ cleaner */
1510
+
1511
+ [data-mesub-dialog] {
1512
+ padding: 14px 28px 28px;
1513
+ border-color: color-mix(in srgb, var(--_text) 7%, transparent);
1514
+ --_shadow: var(--mesub-shadow, 0 1px 1px rgb(20 21 26 / 4%), 0 32px 72px -28px rgb(20 21 26 / 38%));
1515
+ }
1516
+ [data-mesub-dialog]:is([data-mesub-theme="dark"], [data-mesub-theme="dark"] *) {
1517
+ --_shadow: var(--mesub-shadow, 0 0 0 1px rgb(255 255 255 / 5%), 0 32px 80px -24px rgb(0 0 0 / 80%));
1518
+ }
1519
+ [data-mesub-dialog][open] {
1520
+ row-gap: 18px;
1521
+ }
1522
+ [data-mesub-brand] {
1523
+ gap: 8px;
1524
+ color: var(--_text-soft);
1525
+ font-size: 14px;
1526
+ line-height: 18px;
1527
+ }
1528
+ [data-mesub-brand] :is(img, svg) {
1529
+ block-size: 18px;
1530
+ opacity: 0.9;
1531
+ }
1532
+ [data-mesub-dialog] h2 + p {
1533
+ color: var(--_muted);
1534
+ }
1535
+ [data-mesub-merchant] img,
1536
+ [data-mesub-hero] img {
1537
+ box-shadow: none;
1538
+ outline: 1px solid var(--_divider);
1539
+ outline-offset: -1px;
1540
+ }
1541
+ [data-mesub-hero]:is([data-mesub-hero="wait"], [data-mesub-hero="error"], [data-mesub-hero="pending"]) img {
1542
+ outline: 0;
1543
+ }
1544
+ [data-mesub-summary] {
1545
+ padding: 0;
1546
+ border-block: 1px solid var(--_divider);
1547
+ border-radius: 0;
1548
+ background: none;
1549
+ }
1550
+ [data-mesub-wallets] [data-mesub-wallet],
1551
+ [data-mesub-install] {
1552
+ border: 1px solid var(--_border);
1553
+ background: var(--_bg);
1554
+ }
1555
+ [data-mesub-wallets] [data-mesub-wallet]:hover:not(:disabled),
1556
+ [data-mesub-install]:hover {
1557
+ border-color: color-mix(in srgb, var(--_accent) 60%, transparent);
1558
+ background: var(--_bg);
1559
+ box-shadow: 0 6px 16px -10px color-mix(in srgb, var(--_accent) 50%, transparent);
1560
+ }
1561
+
1562
+ /* the wait ring becomes a soft conic arc */
1563
+ [data-mesub-hero="wait"]::before,
1564
+ [data-mesub-hero="pending"]::before {
1565
+ border: 0 !important;
1566
+ background: conic-gradient(from 0deg, transparent 0 50%, var(--_ring, var(--_accent)));
1567
+ -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
1568
+ mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
1569
+ }
1570
+ [data-mesub-hero="pending"] {
1571
+ --_ring: var(--_warning);
1572
+ }
1573
+ [data-mesub-hero][data-mesub-hero="error"]::before {
1574
+ border-color: color-mix(in srgb, var(--_danger) 55%, transparent);
1575
+ }
1576
+
1577
+ /* ------------------------------------------------------------- motion */
1578
+
1579
+ /* review: the terms to sign, closed by default (native <details>) */
1580
+ [data-mesub-terms] {
1581
+ margin: 0;
1582
+ border-block: 1px solid var(--_divider);
1583
+ }
1584
+ [data-mesub-terms] > summary {
1585
+ display: flex;
1586
+ align-items: center;
1587
+ justify-content: space-between;
1588
+ gap: 12px;
1589
+ min-block-size: 44px;
1590
+ list-style: none;
1591
+ color: var(--_text-soft);
1592
+ font-size: 13px;
1593
+ line-height: 18px;
1594
+ font-weight: 500;
1595
+ cursor: pointer;
1596
+ border-radius: var(--_radius);
1597
+ transition: color var(--_dur) ease-out;
1598
+ }
1599
+ [data-mesub-terms] > summary::-webkit-details-marker {
1600
+ display: none;
1601
+ }
1602
+ [data-mesub-terms] > summary::after {
1603
+ content: "";
1604
+ flex: none;
1605
+ inline-size: 7px;
1606
+ block-size: 7px;
1607
+ margin-inline-end: 4px;
1608
+ border-inline-end: 1.5px solid currentColor;
1609
+ border-block-end: 1.5px solid currentColor;
1610
+ transform: translateY(-2px) rotate(45deg);
1611
+ }
1612
+ [data-mesub-terms][open] > summary::after {
1613
+ transform: translateY(2px) rotate(225deg);
1614
+ }
1615
+ [data-mesub-terms] > summary:hover {
1616
+ color: var(--_text);
1617
+ }
1618
+ [data-mesub-terms] [data-mesub-summary] {
1619
+ border-block-end: 0;
1620
+ }
1621
+ [data-mesub-terms] [data-mesub-summary] + p {
1622
+ margin: 0;
1623
+ padding-block: 2px 14px;
1624
+ }
1625
+
1626
+ @media (prefers-reduced-motion: no-preference) {
1627
+
1628
+ [data-mesub-dialog][open] {
1629
+ animation: mesub-enter-v5 380ms var(--_ease-enter);
1630
+ }
1631
+ [data-mesub-dialog][open]::before {
1632
+ transition: background-size 600ms cubic-bezier(0.3, 1.25, 0.5, 1);
1633
+ }
1634
+
1635
+ /* each step's content rises in, one element after another */
1636
+ [data-mesub-dialog][open] > :not([data-mesub-close], [data-mesub-back]:empty, [data-mesub-brand]) {
1637
+ animation: mesub-rise 420ms var(--_ease-enter) both;
1638
+ }
1639
+ [data-mesub-dialog][open] > :nth-child(4) { animation-delay: 0ms; }
1640
+ [data-mesub-dialog][open] > :nth-child(5) { animation-delay: 45ms; }
1641
+ [data-mesub-dialog][open] > :nth-child(6) { animation-delay: 90ms; }
1642
+ [data-mesub-dialog][open] > :nth-child(7) { animation-delay: 135ms; }
1643
+ [data-mesub-dialog][open] > :nth-child(8) { animation-delay: 180ms; }
1644
+ [data-mesub-dialog][open] > :nth-child(9) { animation-delay: 225ms; }
1645
+ [data-mesub-dialog][open] > :nth-child(n+10) { animation-delay: 270ms; }
1646
+
1647
+ [data-mesub-wallets] > li > [data-mesub-wallet],
1648
+ [data-mesub-summary] > [data-mesub-row],
1649
+ [data-mesub-no-wallet] > [data-mesub-install] {
1650
+ animation: mesub-rise 420ms var(--_ease-enter) both;
1651
+ }
1652
+ [data-mesub-wallets] > li:nth-child(1) > [data-mesub-wallet],
1653
+ [data-mesub-summary] > [data-mesub-row]:nth-child(1),
1654
+ [data-mesub-no-wallet] > [data-mesub-install]:nth-of-type(1) { animation-delay: 120ms; }
1655
+ [data-mesub-wallets] > li:nth-child(2) > [data-mesub-wallet],
1656
+ [data-mesub-summary] > [data-mesub-row]:nth-child(2),
1657
+ [data-mesub-no-wallet] > [data-mesub-install]:nth-of-type(2) { animation-delay: 170ms; }
1658
+ [data-mesub-wallets] > li:nth-child(3) > [data-mesub-wallet],
1659
+ [data-mesub-summary] > [data-mesub-row]:nth-child(3) { animation-delay: 220ms; }
1660
+ [data-mesub-wallets] > li:nth-child(n+4) > [data-mesub-wallet],
1661
+ [data-mesub-summary] > [data-mesub-row]:nth-child(n+4) { animation-delay: 270ms; }
1662
+
1663
+ /* press and hover */
1664
+ :is([data-mesub-submit], [data-mesub-done], [data-mesub-subscribe], [data-mesub-reload], [data-mesub-wallet], [data-mesub-install]) {
1665
+ transition-property: color, background-color, border-color, box-shadow, transform;
1666
+ transition-duration: var(--_dur), var(--_dur), var(--_dur), 200ms, 120ms;
1667
+ transition-timing-function: ease-out;
1668
+ }
1669
+ :is([data-mesub-submit], [data-mesub-done], [data-mesub-subscribe], [data-mesub-reload]):active:not(:disabled, [aria-busy="true"]) {
1670
+ transform: scale(0.98);
1671
+ }
1672
+ [data-mesub-wallets] [data-mesub-wallet]:hover:not(:disabled),
1673
+ [data-mesub-install]:hover {
1674
+ transform: translateY(-1px);
1675
+ }
1676
+ [data-mesub-wallets] [data-mesub-wallet]:active:not(:disabled) {
1677
+ transform: scale(0.99);
1678
+ }
1679
+
1680
+ /* busy primary: a light sweep across the button */
1681
+ :is([data-mesub-submit][aria-busy="true"], [data-mesub-subscribe]:is([data-mesub-state="signing"], [data-mesub-state="confirming"])) {
1682
+ background-image: linear-gradient(100deg, transparent 30%, rgb(255 255 255 / 22%) 50%, transparent 70%);
1683
+ background-size: 220% 100%;
1684
+ animation: mesub-shimmer 1400ms linear infinite;
1685
+ }
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+
1693
+ /* heroes */
1694
+ [data-mesub-hero="pending"]::before {
1695
+ animation-duration: 2400ms;
1696
+ }
1697
+ [data-mesub-dialog][open] > [data-mesub-hero="error"] {
1698
+ animation: mesub-rise 420ms var(--_ease-enter) both, mesub-shake 420ms ease-out 380ms;
1699
+ }
1700
+ [data-mesub-hero="error"]::after {
1701
+ animation: mesub-badge 420ms cubic-bezier(0.34, 1.56, 0.64, 1) 260ms both;
1702
+ }
1703
+ [data-mesub-hero="check"]::before {
1704
+ animation: mesub-check 760ms var(--_ease-enter) both;
1705
+ }
1706
+ [data-mesub-hero="check"]::after {
1707
+ content: "";
1708
+ position: absolute;
1709
+ inset: 8px;
1710
+ border: 2px solid var(--_success);
1711
+ border-radius: 50%;
1712
+ animation: mesub-ripple 900ms ease-out 380ms both;
1713
+ }
1714
+
1715
+
1716
+ [data-mesub-merchant] img {
1717
+ animation: mesub-pop-circle 460ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
1718
+ }
1719
+
1720
+ /* money status and alerts arrive last */
1721
+ [data-mesub-funds] {
1722
+ animation: mesub-rise 420ms var(--_ease-enter) 300ms both !important;
1723
+ }
1724
+ [data-mesub-badge] {
1725
+ animation: mesub-badge 380ms cubic-bezier(0.34, 1.56, 0.64, 1) 360ms both;
1726
+ }
1727
+
1728
+ /* terms open and close smoothly where the browser can animate to auto */
1729
+ [data-mesub-terms] {
1730
+ interpolate-size: allow-keywords;
1731
+ }
1732
+ [data-mesub-terms]::details-content {
1733
+ block-size: 0;
1734
+ overflow: hidden;
1735
+ transition: block-size 320ms var(--_ease-enter), content-visibility 320ms allow-discrete;
1736
+ }
1737
+ [data-mesub-terms][open]::details-content {
1738
+ block-size: auto;
1739
+ }
1740
+ [data-mesub-terms] > summary::after {
1741
+ transition: transform 240ms var(--_ease-enter);
1742
+ }
1743
+
1744
+ /* subscribe button: label swaps fade */
1745
+ [data-mesub-subscribe][data-mesub-state="subscribed"]::before {
1746
+ animation: mesub-badge 380ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
1747
+ }
1748
+ }
1749
+
1750
+ @keyframes mesub-enter-v5 {
1751
+ from { opacity: 0; transform: translateY(14px) scale(0.97); filter: blur(6px); }
1752
+ }
1753
+ @keyframes mesub-rise {
1754
+ from { opacity: 0; transform: translateY(8px); }
1755
+ }
1756
+ @keyframes mesub-shimmer {
1757
+ from { background-position: 120% 0; }
1758
+ to { background-position: -120% 0; }
1759
+ }
1760
+ @keyframes mesub-badge {
1761
+ from { transform: scale(0); }
1762
+ }
1763
+ @keyframes mesub-check {
1764
+ 0% { opacity: 0; transform: rotate(45deg) scale(0.4); background-size: 0 3px, 3px 0; background-position: 21px 29px, 27px 32px; }
1765
+ 35% { opacity: 1; transform: rotate(45deg) scale(1.06); background-size: 0 3px, 3px 0; background-position: 21px 29px, 27px 32px; }
1766
+ 60% { transform: rotate(45deg) scale(1); background-size: 9px 3px, 3px 0; background-position: 21px 29px, 27px 32px; }
1767
+ 100% { transform: rotate(45deg) scale(1); background-size: 9px 3px, 3px 14.5px; background-position: 21px 29px, 27px 17.5px; }
1768
+ }
1769
+ @keyframes mesub-ripple {
1770
+ from { opacity: 0.7; transform: scale(0.85); }
1771
+ to { opacity: 0; transform: scale(1.55); }
1772
+ }
1773
+ @keyframes mesub-pop-circle {
1774
+ from { opacity: 0; transform: scale(0.6); }
1775
+ }
1776
+
1777
+ /* ------------------------------------------- mobile: bottom sheet < 480px */
1778
+
1779
+ @media (max-width: 479.98px) {
1780
+ [data-mesub-dialog] {
1781
+ inline-size: 100%;
1782
+ max-inline-size: 100%;
1783
+ max-block-size: calc(100dvh - 24px);
1784
+ margin: auto 0 0;
1785
+ padding: 24px 16px calc(16px + env(safe-area-inset-bottom, 0px));
1786
+ border-block-end: 0;
1787
+ border-radius: var(--_radius-lg) var(--_radius-lg) 0 0;
1788
+ }
1789
+ [data-mesub-dialog][open] {
1790
+ animation-name: mesub-sheet;
1791
+ }
1792
+ [data-mesub-dialog] h2 {
1793
+ font-size: 20px;
1794
+ line-height: 26px;
1795
+ }
1796
+
1797
+ [data-mesub-close] {
1798
+ inset-block-start: 8px;
1799
+ inset-inline-end: 8px;
1800
+ inline-size: 44px;
1801
+ block-size: 44px;
1802
+ }
1803
+ [data-mesub-back] {
1804
+ min-block-size: 44px;
1805
+ }
1806
+ [data-mesub-wallet] {
1807
+ min-block-size: 56px;
1808
+ }
1809
+ }
1810
+ /* ------------------------------------------------------------- the token
1811
+ * img[data-mesub-token-logo] before an amount; small[data-mesub-usd] and
1812
+ * small[data-mesub-unverified] under the checkout's price.
1813
+ */
1814
+
1815
+ /* a fixed box under the line's own height: loaded, failed or absent, nothing moves */
1816
+ [data-mesub-token-logo] {
1817
+ display: inline-block;
1818
+ inline-size: 20px;
1819
+ block-size: 20px;
1820
+ margin-inline-end: 6px;
1821
+ border-radius: 50%;
1822
+ object-fit: cover;
1823
+ vertical-align: middle;
1824
+ }
1825
+ [data-mesub-price] [data-mesub-token-logo] {
1826
+ inline-size: 28px;
1827
+ block-size: 28px;
1828
+ margin-inline-end: 8px;
1829
+ }
1830
+ [data-mesub-rate] [data-mesub-token-logo] {
1831
+ inline-size: 16px;
1832
+ block-size: 16px;
1833
+ }
1834
+ [data-mesub-price] strong {
1835
+ max-inline-size: 100%;
1836
+ overflow-wrap: anywhere;
1837
+ text-align: center;
1838
+ }
1839
+ [data-mesub-price] small {
1840
+ color: var(--_muted);
1841
+ font-size: 13px;
1842
+ line-height: 18px;
1843
+ text-align: center;
1844
+ }
1845
+ [data-mesub-terms] [data-mesub-row] dd small {
1846
+ display: block;
1847
+ }
1848
+ /* the dollars at the charge, under the amount: within the row's own height */
1849
+ [data-mesub-payment] > span:last-child small {
1850
+ display: block;
1851
+ line-height: 16px;
1852
+ font-weight: 400;
1853
+ }
1854
+
1855
+ /* ------------------------------------------------------- long amounts
1856
+ * An amount left in full digits never leaves its box: [data-mesub-fit] is set
1857
+ * past a length ("2", "3", "4"), the text shrinks, then breaks anywhere.
1858
+ * Ordinary amounts carry no attribute and keep their size.
1859
+ */
1860
+ [data-mesub-price] strong[data-mesub-fit] {
1861
+ min-inline-size: 0;
1862
+ }
1863
+ /* one line of the same height as an ordinary price */
1864
+ [data-mesub-price] strong[data-mesub-fit="2"] {
1865
+ font-size: 28px;
1866
+ letter-spacing: -0.02em;
1867
+ }
1868
+ /* two lines within that height */
1869
+ [data-mesub-price] strong[data-mesub-fit="3"] {
1870
+ font-size: 20px;
1871
+ line-height: 23px;
1872
+ letter-spacing: -0.01em;
1873
+ }
1874
+ [data-mesub-price] strong[data-mesub-fit="4"] {
1875
+ font-size: 16px;
1876
+ line-height: 23px;
1877
+ letter-spacing: 0;
1878
+ }
1879
+ [data-mesub-price] strong:is([data-mesub-fit="3"], [data-mesub-fit="4"]) [data-mesub-token-logo] {
1880
+ inline-size: 18px;
1881
+ block-size: 18px;
1882
+ margin-inline-end: 6px;
1883
+ }
1884
+ /* two lines fit the button's own height */
1885
+ [data-mesub-submit]:is([data-mesub-fit="3"], [data-mesub-fit="4"]) {
1886
+ padding-block: 5px;
1887
+ font-size: 13px;
1888
+ line-height: 18px;
1889
+ white-space: normal;
1890
+ overflow-wrap: anywhere;
1891
+ }
1892
+ [data-mesub-row] dt {
1893
+ flex: none;
1894
+ }
1895
+ [data-mesub-row] dd {
1896
+ min-inline-size: 0;
1897
+ overflow-wrap: anywhere;
1898
+ }
1899
+ [data-mesub-dialog] p[data-mesub-rate],
1900
+ [data-mesub-subscription-price] {
1901
+ min-inline-size: 0;
1902
+ overflow-wrap: anywhere;
1903
+ }
1904
+ [data-mesub-rate] strong:is([data-mesub-fit="3"], [data-mesub-fit="4"]) {
1905
+ font-size: 20px;
1906
+ line-height: 26px;
1907
+ letter-spacing: -0.01em;
1908
+ }
1909
+ [data-mesub-subscription-price] strong:is([data-mesub-fit="3"], [data-mesub-fit="4"]) {
1910
+ font-size: 16px;
1911
+ line-height: 22px;
1912
+ }
1913
+ /* a payment in full digits: on a line of its own under the date and the word */
1914
+ [data-mesub-payment] > span:last-child {
1915
+ min-inline-size: 0;
1916
+ overflow-wrap: anywhere;
1917
+ }
1918
+ [data-mesub-payment] > span[data-mesub-fit] {
1919
+ grid-column: 1 / -1;
1920
+ padding-block-end: 8px;
1921
+ }
1922
+
1923
+ @media (max-width: 479.98px) {
1924
+ [data-mesub-dialog] { padding: 24px 16px calc(16px + env(safe-area-inset-bottom, 0px)); }
1925
+ [data-mesub-close] { inset-block-start: 10px; inset-inline-end: 8px; inline-size: 44px; block-size: 44px; }
1926
+ [data-mesub-dialog] > [data-mesub-back]:empty { inset-block-start: 10px; inset-inline-start: 8px; inline-size: 44px; block-size: 44px; }
1927
+ [data-mesub-dialog] { padding-block-start: 14px; }
1928
+
1929
+ [data-mesub-price] strong { font-size: 40px; line-height: 44px; }
1930
+ [data-mesub-price] strong[data-mesub-fit="2"] { font-size: 24px; }
1931
+ [data-mesub-price] strong[data-mesub-fit="3"] { font-size: 18px; line-height: 22px; }
1932
+ [data-mesub-price] strong[data-mesub-fit="4"] { font-size: 15px; line-height: 22px; }
1933
+ [data-mesub-wallets] [data-mesub-wallet], [data-mesub-install] { min-block-size: 60px; }
1934
+ }
1935
+
1936
+ /* ---------------------------------------------------------------- motion */
1937
+
1938
+ @keyframes mesub-enter {
1939
+ from { opacity: 0; transform: translateY(8px) scale(0.98); }
1940
+ }
1941
+ @keyframes mesub-sheet {
1942
+ from { transform: translateY(100%); }
1943
+ }
1944
+ @keyframes mesub-fade {
1945
+ from { opacity: 0; }
1946
+ }
1947
+ @keyframes mesub-spin {
1948
+ to { transform: rotate(360deg); }
1949
+ }
1950
+
1951
+ /* ============================================================ CHECKOUT
1952
+ * What the rebuilt flow adds to the handoff: p[data-mesub-description] under the
1953
+ * price, and the terms inside details[data-mesub-terms].
1954
+ */
1955
+
1956
+ [data-mesub-description] {
1957
+ margin-block-start: -8px;
1958
+ color: var(--_muted);
1959
+ text-align: center;
1960
+ }
1961
+ /* the plan's end date, under its price: part of what is bought */
1962
+ [data-mesub-ends] {
1963
+ margin-block-start: -8px;
1964
+ color: var(--_text-soft);
1965
+ font-size: 13px;
1966
+ text-align: center;
1967
+ }
1968
+ [data-mesub-terms] [data-mesub-message] {
1969
+ margin-block-end: 14px;
1970
+ }
1971
+ /* Right under the list, the terms are its next row: one divider between them,
1972
+ not two with the view's gap in the middle. */
1973
+ [data-mesub-summary] + [data-mesub-terms] {
1974
+ margin-block-start: -16px;
1975
+ border-block-start: 0;
1976
+ }
1977
+ /* the last line of the review, right above the button */
1978
+ [data-mesub-footnote] {
1979
+ margin: 0;
1980
+ color: var(--_muted);
1981
+ font-size: 12px;
1982
+ line-height: 18px;
1983
+ text-align: center;
1984
+ }
1985
+ /* What the toggle opens: set in from the list above and lighter than it, with
1986
+ a rule down its side, so it reads as the toggle's own content and not as
1987
+ more rows of that list. */
1988
+ [data-mesub-terms] [data-mesub-summary] {
1989
+ margin: 0 0 14px;
1990
+ padding: 2px 0 2px 14px;
1991
+ border: 0;
1992
+ border-inline-start: 2px solid var(--_border);
1993
+ border-radius: 0;
1994
+ background: transparent;
1995
+ }
1996
+ /* A term can be a sentence: its name sits above it and both start at the same
1997
+ edge, so a long one wraps under its own first word at any width, and no
1998
+ column is there for it to spill out of. */
1999
+ [data-mesub-terms] [data-mesub-row] {
2000
+ display: block;
2001
+ min-block-size: 0;
2002
+ padding-block: 6px;
2003
+ font-size: 12px;
2004
+ line-height: 18px;
2005
+ }
2006
+ [data-mesub-terms] [data-mesub-row] + [data-mesub-row] {
2007
+ border-block-start: 0;
2008
+ }
2009
+ [data-mesub-terms] [data-mesub-row] dt {
2010
+ color: var(--_muted);
2011
+ }
2012
+ [data-mesub-terms] [data-mesub-row] dd {
2013
+ display: block;
2014
+ color: var(--_text-soft);
2015
+ font-size: 13px;
2016
+ font-weight: 400;
2017
+ text-align: start;
2018
+ overflow-wrap: anywhere;
2019
+ }
2020
+ /* the token, as a small button that opens where it is traded */
2021
+ [data-mesub-dialog] a[data-mesub-token] {
2022
+ display: inline-flex;
2023
+ align-items: center;
2024
+ gap: 4px;
2025
+ min-block-size: 26px;
2026
+ /* under its name, not beside it: clear of the line above */
2027
+ margin-block: 3px 0;
2028
+ padding: 0 10px;
2029
+ border: 1px solid var(--_border);
2030
+ border-radius: 999px;
2031
+ color: var(--_text);
2032
+ font-weight: 500;
2033
+ text-decoration: none;
2034
+ transition: background-color var(--_dur) ease-out;
2035
+ }
2036
+ [data-mesub-dialog] a[data-mesub-token]::after {
2037
+ content: "\2197";
2038
+ color: var(--_muted);
2039
+ font-size: 11px;
2040
+ }
2041
+ [data-mesub-dialog] a[data-mesub-token]:hover {
2042
+ background: var(--_sunk);
2043
+ }
2044
+ [data-mesub-dialog] a[data-mesub-token]:focus-visible {
2045
+ outline: 2px solid var(--_accent);
2046
+ outline-offset: 2px;
2047
+ }
2048
+ @media (prefers-reduced-motion: reduce) {
2049
+ [data-mesub-dialog] a[data-mesub-token] {
2050
+ transition: none;
2051
+ }
2052
+ }
2053
+ /* where the subscription is stopped: a quiet button on the done screen, opening that page */
2054
+ [data-mesub-dialog] a[data-mesub-manage] {
2055
+ display: flex;
2056
+ align-items: center;
2057
+ justify-content: center;
2058
+ gap: 6px;
2059
+ min-block-size: 40px;
2060
+ margin: 0;
2061
+ border: 1px solid var(--_border);
2062
+ border-radius: var(--_radius);
2063
+ color: var(--_text);
2064
+ font-size: 13px;
2065
+ line-height: 18px;
2066
+ font-weight: 500;
2067
+ text-decoration: none;
2068
+ transition: background-color var(--_dur) ease-out;
2069
+ }
2070
+ /* the arrow only when it leaves the site */
2071
+ [data-mesub-dialog] a[data-mesub-manage][data-mesub-external]::after {
2072
+ content: "\2197";
2073
+ color: var(--_muted);
2074
+ font-size: 12px;
2075
+ }
2076
+ [data-mesub-dialog] a[data-mesub-manage]:hover {
2077
+ background: var(--_sunk);
2078
+ }
2079
+ [data-mesub-dialog] a[data-mesub-manage]:focus-visible {
2080
+ outline: 2px solid var(--_accent);
2081
+ outline-offset: 2px;
2082
+ }
2083
+ @media (prefers-reduced-motion: reduce) {
2084
+ [data-mesub-dialog] a[data-mesub-manage] {
2085
+ transition: none;
2086
+ }
2087
+ }
2088
+ /* Cancel takes the room of the button above it, so its hover is as wide */
2089
+ [data-mesub-cancel] {
2090
+ justify-self: stretch;
2091
+ inline-size: 100%;
2092
+ min-block-size: 48px;
2093
+ border-radius: var(--_radius-lg);
2094
+ }
2095
+ [data-mesub-done]:disabled {
2096
+ background: var(--_sunk);
2097
+ color: var(--_muted);
2098
+ cursor: not-allowed;
2099
+ }
2100
+ :is([data-mesub-cancel], [data-mesub-reload]):disabled {
2101
+ background: transparent;
2102
+ color: var(--_muted);
2103
+ cursor: not-allowed;
2104
+ }
2105
+
2106
+ /* ============================================================== MANAGE
2107
+ * <ManageSubscriptions />, in the page, not in a dialog:
2108
+ * div[data-mesub-subscriptions][data-mesub-state] > ul[data-mesub-subscription-list]
2109
+ * > li[data-mesub-subscription] > div[data-mesub-subscription-head] (strong + span[data-mesub-status])
2110
+ * + p[data-mesub-subscription-price] + dl[data-mesub-summary]
2111
+ * + div[data-mesub-pay-now] (button + p[data-mesub-pay-now-said]) on a late one + button[data-mesub-action];
2112
+ * p[data-mesub-empty] when there is nothing to list, button[data-mesub-retry] after an error.
2113
+ */
2114
+
2115
+ [data-mesub-subscriptions] {
2116
+ display: grid;
2117
+ gap: 12px;
2118
+ color: var(--_text-soft);
2119
+ font-family: var(--mesub-font, inherit);
2120
+ font-size: 14px;
2121
+ line-height: 20px;
2122
+ text-align: start;
2123
+ }
2124
+ [data-mesub-subscriptions] *,
2125
+ [data-mesub-subscriptions] *::before,
2126
+ [data-mesub-subscriptions] *::after {
2127
+ box-sizing: border-box;
2128
+ }
2129
+ [data-mesub-subscriptions] p {
2130
+ margin: 0;
2131
+ }
2132
+ [data-mesub-subscriptions] > [data-mesub-notice] {
2133
+ justify-content: flex-start;
2134
+ }
2135
+ [data-mesub-subscriptions] > [data-mesub-error] {
2136
+ color: var(--_danger-text);
2137
+ font-size: 13px;
2138
+ line-height: 18px;
2139
+ }
2140
+ [data-mesub-empty] {
2141
+ padding: 16px;
2142
+ border: 1px dashed var(--_border);
2143
+ border-radius: var(--_radius-lg);
2144
+ color: var(--_muted);
2145
+ }
2146
+
2147
+ [data-mesub-subscription-list] {
2148
+ display: grid;
2149
+ gap: 12px;
2150
+ margin: 0;
2151
+ padding: 0;
2152
+ list-style: none;
2153
+ }
2154
+ /* One subscription, as a card: who it is, what it costs, its dates, what to
2155
+ know, then the one thing it allows. Read top to bottom. */
2156
+ [data-mesub-subscription] {
2157
+ display: grid;
2158
+ gap: 12px;
2159
+ padding: 16px;
2160
+ border: 1px solid var(--_border);
2161
+ border-radius: var(--_radius-lg);
2162
+ background: var(--_bg);
2163
+ }
2164
+ [data-mesub-subscription-head] {
2165
+ display: flex;
2166
+ align-items: center;
2167
+ gap: 12px;
2168
+ min-inline-size: 0;
2169
+ }
2170
+ [data-mesub-subscription] [data-mesub-logo] {
2171
+ flex: none;
2172
+ display: grid;
2173
+ place-items: center;
2174
+ inline-size: 40px;
2175
+ block-size: 40px;
2176
+ border-radius: 10px;
2177
+ background: var(--_sunk);
2178
+ color: var(--_text-soft);
2179
+ font-size: 15px;
2180
+ font-weight: 600;
2181
+ object-fit: cover;
2182
+ }
2183
+ [data-mesub-subscription-name] {
2184
+ flex: 1;
2185
+ display: grid;
2186
+ min-inline-size: 0;
2187
+ }
2188
+ [data-mesub-subscription-name] strong {
2189
+ overflow: hidden;
2190
+ color: var(--_text);
2191
+ font-size: 15px;
2192
+ line-height: 20px;
2193
+ font-weight: 600;
2194
+ text-overflow: ellipsis;
2195
+ white-space: nowrap;
2196
+ }
2197
+ [data-mesub-subscription-name] span {
2198
+ overflow: hidden;
2199
+ color: var(--_muted);
2200
+ font-size: 12px;
2201
+ line-height: 16px;
2202
+ text-overflow: ellipsis;
2203
+ white-space: nowrap;
2204
+ }
2205
+ [data-mesub-status] {
2206
+ flex: none;
2207
+ padding: 2px 8px;
2208
+ border-radius: 999px;
2209
+ background: var(--_sunk);
2210
+ color: var(--_text-soft);
2211
+ font-size: 12px;
2212
+ line-height: 16px;
2213
+ font-weight: 500;
2214
+ }
2215
+ [data-mesub-status="active"] {
2216
+ background: var(--_success-soft);
2217
+ color: var(--_success-text);
2218
+ }
2219
+ :is([data-mesub-status="unpaid"], [data-mesub-status="stopped"], [data-mesub-status="paused"]) {
2220
+ background: var(--_warning-soft);
2221
+ color: var(--_warning-text);
2222
+ }
2223
+ [data-mesub-subscription-price] {
2224
+ color: var(--_text-soft);
2225
+ font-variant-numeric: tabular-nums;
2226
+ }
2227
+ [data-mesub-subscription-price] strong {
2228
+ color: var(--_text);
2229
+ font-size: 20px;
2230
+ line-height: 26px;
2231
+ font-weight: 600;
2232
+ letter-spacing: -0.01em;
2233
+ }
2234
+ [data-mesub-subscription] [data-mesub-summary] {
2235
+ border-block-end: 0;
2236
+ }
2237
+ [data-mesub-subscription] [data-mesub-row]:last-child {
2238
+ padding-block-end: 0;
2239
+ }
2240
+ [data-mesub-dialog] [data-mesub-subscription-note],
2241
+ [data-mesub-subscription-note] {
2242
+ text-align: start;
2243
+ color: var(--_muted);
2244
+ font-size: 12px;
2245
+ line-height: 18px;
2246
+ }
2247
+
2248
+ /* the one thing a subscription allows now, and Try again after a failed read */
2249
+ :is([data-mesub-action], [data-mesub-retry]) {
2250
+ display: inline-flex;
2251
+ align-items: center;
2252
+ justify-content: center;
2253
+ min-block-size: 36px;
2254
+ margin: 0;
2255
+ padding: 0 14px;
2256
+ border: 1px solid var(--_control-border);
2257
+ border-radius: var(--_radius);
2258
+ background: var(--_bg);
2259
+ color: var(--_text);
2260
+ font: inherit;
2261
+ font-size: 13px;
2262
+ font-weight: 500;
2263
+ cursor: pointer;
2264
+ transition: border-color var(--_dur) ease-out, background-color var(--_dur) ease-out;
2265
+ }
2266
+ [data-mesub-action] {
2267
+ inline-size: 100%;
2268
+ min-block-size: 40px;
2269
+ }
2270
+ [data-mesub-retry] {
2271
+ justify-self: start;
2272
+ }
2273
+ [data-mesub-action="cancel"] {
2274
+ color: var(--_danger-text);
2275
+ }
2276
+
2277
+ /* Pay now on a late one (Mesub-io/backend#354): the way out, so the accent; what came of it under it */
2278
+ [data-mesub-pay-now] {
2279
+ display: grid;
2280
+ gap: 6px;
2281
+ }
2282
+ [data-mesub-pay-now] [data-mesub-action="pay-now"] {
2283
+ border-color: var(--_accent);
2284
+ background: var(--_accent);
2285
+ color: var(--_on-accent);
2286
+ }
2287
+ [data-mesub-pay-now] [data-mesub-action="pay-now"]:hover:not(:disabled) {
2288
+ border-color: var(--_accent-hover);
2289
+ background: var(--_accent-hover);
2290
+ }
2291
+ [data-mesub-pay-now] [data-mesub-action="pay-now"]:active:not(:disabled) {
2292
+ background: var(--_accent-active);
2293
+ }
2294
+ [data-mesub-pay-now-said] {
2295
+ text-align: start;
2296
+ font-size: 12px;
2297
+ line-height: 18px;
2298
+ color: var(--_success-text);
2299
+ }
2300
+ [data-mesub-pay-now-said="refused"] {
2301
+ color: var(--_danger-text);
2302
+ }
2303
+ :is([data-mesub-action], [data-mesub-retry]):hover:not(:disabled) {
2304
+ background: var(--_sunk);
2305
+ }
2306
+ :is([data-mesub-action], [data-mesub-retry]):active:not(:disabled) {
2307
+ border-color: var(--_text);
2308
+ }
2309
+ :is([data-mesub-action], [data-mesub-retry]):focus-visible {
2310
+ outline: 2px solid var(--_focus);
2311
+ outline-offset: 2px;
2312
+ }
2313
+ :is([data-mesub-action], [data-mesub-retry]):disabled {
2314
+ border-color: var(--_border);
2315
+ color: var(--_muted);
2316
+ cursor: not-allowed;
2317
+ }
2318
+
2319
+ @media (max-width: 479.98px) {
2320
+ :is([data-mesub-action], [data-mesub-retry]) {
2321
+ min-block-size: 44px;
2322
+ }
2323
+ }
2324
+
2325
+ @media (prefers-reduced-motion: reduce) {
2326
+ [data-mesub-dialog][open],
2327
+ [data-mesub-dialog]::backdrop {
2328
+ animation: none;
2329
+ }
2330
+ [data-mesub-dialog] *,
2331
+ [data-mesub-dialog] *::before,
2332
+ [data-mesub-dialog] *::after,
2333
+ [data-mesub-subscriptions] *,
2334
+ [data-mesub-subscriptions] *::before,
2335
+ [data-mesub-subscribe],
2336
+ [data-mesub-subscribe]::before,
2337
+ [data-mesub-subscribe]::after {
2338
+ transition-duration: 0ms !important;
2339
+ animation-duration: 2400ms !important; /* spinners slow to a crawl instead of vanishing */
2340
+ }
2341
+ }
2342
+
2343
+ @media (forced-colors: active) {
2344
+ :is([data-mesub-submit], [data-mesub-subscribe], [data-mesub-wallet], [data-mesub-action], [data-mesub-retry]) {
2345
+ border: 1px solid ButtonText;
2346
+ }
2347
+ }
2348
+
2349
+ /* ============================================================ MANAGE BUTTON
2350
+ * button[data-mesub-manage-button]: the Subscribe button's shape, in neutral
2351
+ * colours, since it opens a list and charges nothing.
2352
+ */
2353
+ [data-mesub-manage-button] {
2354
+ display: inline-flex;
2355
+ align-items: center;
2356
+ justify-content: center;
2357
+ gap: 8px;
2358
+ min-block-size: 44px;
2359
+ margin: 0;
2360
+ padding: 0 20px;
2361
+ border: 1px solid var(--_border);
2362
+ border-radius: var(--_radius);
2363
+ background: var(--_bg);
2364
+ color: var(--_text);
2365
+ font-family: var(--mesub-font, inherit);
2366
+ font-size: 14px;
2367
+ line-height: 20px;
2368
+ font-weight: 500;
2369
+ white-space: nowrap;
2370
+ cursor: pointer;
2371
+ transition-property: background-color, border-color;
2372
+ transition-duration: var(--_dur);
2373
+ transition-timing-function: ease-out;
2374
+ }
2375
+ [data-mesub-manage-button]:hover:not(:disabled) {
2376
+ background: var(--_sunk);
2377
+ }
2378
+ [data-mesub-manage-button]:focus-visible {
2379
+ outline: 2px solid var(--_accent);
2380
+ outline-offset: 2px;
2381
+ }
2382
+ [data-mesub-manage-button]:disabled {
2383
+ color: var(--_muted);
2384
+ cursor: not-allowed;
2385
+ }
2386
+ @media (prefers-reduced-motion: reduce) {
2387
+ [data-mesub-manage-button] {
2388
+ transition: none;
2389
+ }
2390
+ }
2391
+
2392
+ /* ============================================================ ONE SUBSCRIPTION
2393
+ * [data-mesub-step="subscription"]: what the Manage button opens. Read top to
2394
+ * bottom: who and what, how it stands, the facts, what comes and what was
2395
+ * charged, then the one thing it allows. No card inside the window: the
2396
+ * window is the frame, hairlines do the grouping.
2397
+ */
2398
+ [data-mesub-step="subscription"] {
2399
+ text-align: start;
2400
+ }
2401
+ [data-mesub-identity] {
2402
+ grid-column: 1 / -1;
2403
+ display: flex;
2404
+ align-items: center;
2405
+ gap: 12px;
2406
+ min-inline-size: 0;
2407
+ }
2408
+ [data-mesub-identity] [data-mesub-logo] {
2409
+ flex: none;
2410
+ display: grid;
2411
+ place-items: center;
2412
+ inline-size: 44px;
2413
+ block-size: 44px;
2414
+ border-radius: 12px;
2415
+ background: var(--_sunk);
2416
+ color: var(--_text-soft);
2417
+ font-size: 16px;
2418
+ font-weight: 600;
2419
+ object-fit: cover;
2420
+ }
2421
+ [data-mesub-identity] > div {
2422
+ flex: 1;
2423
+ display: grid;
2424
+ min-inline-size: 0;
2425
+ }
2426
+ [data-mesub-dialog] [data-mesub-identity] h2 {
2427
+ overflow: hidden;
2428
+ padding: 0;
2429
+ font-size: 17px;
2430
+ line-height: 22px;
2431
+ text-align: start;
2432
+ text-overflow: ellipsis;
2433
+ white-space: nowrap;
2434
+ }
2435
+ [data-mesub-identity] > div > span {
2436
+ overflow: hidden;
2437
+ color: var(--_muted);
2438
+ font-size: 13px;
2439
+ line-height: 18px;
2440
+ text-overflow: ellipsis;
2441
+ white-space: nowrap;
2442
+ }
2443
+ [data-mesub-dialog] p[data-mesub-rate] {
2444
+ grid-column: 1 / -1;
2445
+ margin: 0;
2446
+ color: var(--_text-soft);
2447
+ font-size: 14px;
2448
+ line-height: 20px;
2449
+ text-align: start;
2450
+ font-variant-numeric: tabular-nums;
2451
+ }
2452
+ [data-mesub-rate] strong {
2453
+ color: var(--_text);
2454
+ font-size: 28px;
2455
+ line-height: 32px;
2456
+ font-weight: 600;
2457
+ letter-spacing: -0.02em;
2458
+ }
2459
+ [data-mesub-dialog] p[data-mesub-state-note] {
2460
+ grid-column: 1 / -1;
2461
+ margin: -8px 0 0;
2462
+ color: var(--_text-soft);
2463
+ font-size: 13px;
2464
+ line-height: 18px;
2465
+ text-align: start;
2466
+ }
2467
+ [data-mesub-step="subscription"] > [data-mesub-summary] {
2468
+ grid-column: 1 / -1;
2469
+ }
2470
+
2471
+ /* Payments: the checkout's toggle, opening on two groups, what comes and what
2472
+ was charged. Each line has three columns: the date, the word, the amount. */
2473
+ [data-mesub-step="subscription"] > [data-mesub-payments] {
2474
+ grid-column: 1 / -1;
2475
+ }
2476
+ [data-mesub-payments] > section {
2477
+ display: grid;
2478
+ gap: 2px;
2479
+ padding-inline-start: 14px;
2480
+ border-inline-start: 2px solid var(--_border);
2481
+ }
2482
+ [data-mesub-payments] > section + section {
2483
+ margin-block-start: 12px;
2484
+ }
2485
+ [data-mesub-payments] > section:last-child {
2486
+ margin-block-end: 14px;
2487
+ }
2488
+ [data-mesub-payments] h3 {
2489
+ margin: 0;
2490
+ color: var(--_muted);
2491
+ font-size: 11px;
2492
+ line-height: 16px;
2493
+ font-weight: 600;
2494
+ letter-spacing: 0.06em;
2495
+ text-transform: uppercase;
2496
+ }
2497
+ [data-mesub-payments] ul {
2498
+ display: grid;
2499
+ /* One set of columns for every row: the date takes the width of the longest one. */
2500
+ grid-template-columns: max-content minmax(0, 1fr) auto;
2501
+ grid-auto-rows: max-content;
2502
+ column-gap: 12px;
2503
+ margin: 0;
2504
+ padding: 0;
2505
+ list-style: none;
2506
+ }
2507
+ /* the rest of the history, asked for: a quiet line, never a second button */
2508
+ [data-mesub-dialog] [data-mesub-more] {
2509
+ justify-self: start;
2510
+ min-block-size: 32px;
2511
+ margin: 4px 0 0;
2512
+ padding: 0;
2513
+ border: 0;
2514
+ background: none;
2515
+ color: var(--_muted);
2516
+ font: inherit;
2517
+ font-size: 13px;
2518
+ text-decoration: underline;
2519
+ text-underline-offset: 3px;
2520
+ cursor: pointer;
2521
+ }
2522
+ [data-mesub-dialog] [data-mesub-more]:hover {
2523
+ color: var(--_text);
2524
+ }
2525
+ [data-mesub-payment] {
2526
+ display: grid;
2527
+ grid-column: 1 / -1;
2528
+ grid-template-columns: subgrid;
2529
+ align-items: center;
2530
+ min-block-size: 36px;
2531
+ font-size: 13px;
2532
+ line-height: 18px;
2533
+ font-variant-numeric: tabular-nums;
2534
+ }
2535
+ [data-mesub-payment] + [data-mesub-payment] {
2536
+ border-block-start: 1px solid var(--_divider);
2537
+ }
2538
+ [data-mesub-payment] > span:first-child {
2539
+ color: var(--_muted);
2540
+ /* A date with its hour and time zone stays on one line. */
2541
+ white-space: nowrap;
2542
+ }
2543
+ /* the word, with a dot of its tone before it */
2544
+ [data-mesub-payment] > span:nth-child(2) {
2545
+ display: flex;
2546
+ align-items: center;
2547
+ gap: 8px;
2548
+ min-inline-size: 0;
2549
+ color: var(--_text);
2550
+ }
2551
+ [data-mesub-payment] > span:nth-child(2)::before {
2552
+ content: "";
2553
+ flex: none;
2554
+ inline-size: 6px;
2555
+ block-size: 6px;
2556
+ border-radius: 50%;
2557
+ background: var(--_muted);
2558
+ }
2559
+ /* which retry, 2 / 3: quieter than the word it follows */
2560
+ [data-mesub-payment] small {
2561
+ color: var(--_muted);
2562
+ font-size: 12px;
2563
+ white-space: nowrap;
2564
+ }
2565
+ [data-mesub-payment="good"] > span:nth-child(2)::before {
2566
+ background: var(--_success);
2567
+ }
2568
+ [data-mesub-payment="bad"] > span:nth-child(2)::before {
2569
+ background: var(--_danger);
2570
+ }
2571
+ /* not yet: a hollow dot and softer words, so it cannot read as a charge made */
2572
+ [data-mesub-payment="upcoming"] > span:nth-child(2) {
2573
+ color: var(--_text-soft);
2574
+ }
2575
+ [data-mesub-payment="upcoming"] > span:nth-child(2)::before {
2576
+ border: 1.5px solid var(--_muted);
2577
+ background: transparent;
2578
+ }
2579
+ [data-mesub-payment] > span:last-child {
2580
+ color: var(--_text);
2581
+ font-weight: 500;
2582
+ text-align: end;
2583
+ }
2584
+ /* only what was paid is bold: an amount not taken, or not yet, reads softer */
2585
+ :is([data-mesub-payment="upcoming"], [data-mesub-payment="bad"], [data-mesub-payment="none"])
2586
+ > span:last-child {
2587
+ color: var(--_text-soft);
2588
+ font-weight: 400;
2589
+ }
2590
+ [data-mesub-dialog] [data-mesub-payment] a {
2591
+ color: inherit;
2592
+ text-decoration: underline;
2593
+ text-decoration-color: var(--_border);
2594
+ text-underline-offset: 3px;
2595
+ }
2596
+ [data-mesub-dialog] [data-mesub-payment] a:hover {
2597
+ text-decoration-color: currentColor;
2598
+ }
2599
+
2600
+ /* the one action: full width, neutral, the rarest thing on the screen */
2601
+ [data-mesub-step="subscription"] > [data-mesub-action] {
2602
+ grid-column: 1 / -1;
2603
+ inline-size: 100%;
2604
+ min-block-size: 44px;
2605
+ border-color: var(--_border);
2606
+ border-radius: var(--_radius-lg);
2607
+ }
2608
+ [data-mesub-step="subscription"] > [data-mesub-retry] {
2609
+ grid-column: 1 / -1;
2610
+ }
2611
+
2612
+ /* the list inside the dialog: the dialog is the frame, the list brings none */
2613
+ [data-mesub-dialog] [data-mesub-subscriptions][data-mesub-in-dialog] {
2614
+ grid-column: 1 / -1;
2615
+ }
2616
+
2617
+
2618
+ /* ============================================================ MANAGE, THE CHECKOUT'S LOOK
2619
+ * The Manage window and the list in a page read like the checkout (#66): a
2620
+ * centred head with the merchant's logo, the price large, the note centred
2621
+ * above the buttons, Pay now as the checkout's primary, the one action as its
2622
+ * quiet filled button, and what Pay now came to as a centred line.
2623
+ */
2624
+
2625
+ /* head: logo, name and merchant, status, centred */
2626
+ :is([data-mesub-identity], [data-mesub-subscription-head]) {
2627
+ flex-direction: column;
2628
+ justify-content: center;
2629
+ gap: 8px;
2630
+ text-align: center;
2631
+ }
2632
+ :is([data-mesub-identity], [data-mesub-subscription-head]) [data-mesub-logo],
2633
+ [data-mesub-subscription] [data-mesub-subscription-head] [data-mesub-logo] {
2634
+ inline-size: 56px;
2635
+ block-size: 56px;
2636
+ border-radius: 16px;
2637
+ box-shadow: 0 0 0 1px var(--_border), 0 8px 20px -10px rgb(20 21 26 / 35%);
2638
+ font-size: 20px;
2639
+ }
2640
+ :is([data-mesub-identity] > div, [data-mesub-subscription-name]) {
2641
+ flex: none;
2642
+ justify-items: center;
2643
+ max-inline-size: 100%;
2644
+ }
2645
+ [data-mesub-dialog] [data-mesub-identity] h2 {
2646
+ text-align: center;
2647
+ }
2648
+ [data-mesub-subscription-name] strong {
2649
+ font-size: 17px;
2650
+ line-height: 22px;
2651
+ }
2652
+ [data-mesub-subscription-name] span {
2653
+ font-size: 13px;
2654
+ line-height: 18px;
2655
+ }
2656
+
2657
+ /* the price, large and centred, its period under it */
2658
+ :is([data-mesub-dialog] p[data-mesub-rate], [data-mesub-subscription-price]) {
2659
+ display: grid;
2660
+ justify-items: center;
2661
+ gap: 2px;
2662
+ text-align: center;
2663
+ }
2664
+ :is([data-mesub-rate], [data-mesub-subscription-price]) strong {
2665
+ display: inline-flex;
2666
+ align-items: center;
2667
+ gap: 8px;
2668
+ font-size: 40px;
2669
+ line-height: 44px;
2670
+ letter-spacing: -0.03em;
2671
+ }
2672
+
2673
+ /* the note: the checkout's quiet line above the buttons */
2674
+ :is([data-mesub-dialog] p[data-mesub-state-note], [data-mesub-subscription-note]) {
2675
+ margin: 0;
2676
+ color: var(--_text-soft);
2677
+ font-size: 13px;
2678
+ line-height: 18px;
2679
+ text-align: center;
2680
+ text-wrap: pretty;
2681
+ }
2682
+
2683
+ /* Pay now: the checkout's primary */
2684
+ [data-mesub-step="subscription"] > [data-mesub-pay-now] {
2685
+ grid-column: 1 / -1;
2686
+ }
2687
+ [data-mesub-pay-now] {
2688
+ gap: 8px;
2689
+ }
2690
+ [data-mesub-pay-now] [data-mesub-action="pay-now"] {
2691
+ min-block-size: 48px;
2692
+ border-radius: var(--_radius-lg);
2693
+ font-size: 14px;
2694
+ }
2695
+ [data-mesub-pay-now] [data-mesub-action="pay-now"]:disabled:not([aria-busy="true"]) {
2696
+ border-color: transparent;
2697
+ background: var(--_sunk);
2698
+ color: var(--_muted);
2699
+ font-variant-numeric: tabular-nums;
2700
+ }
2701
+
2702
+ /* the one action (cancel, resume, close): the checkout's quiet filled button */
2703
+ :is([data-mesub-step="subscription"] > [data-mesub-action], [data-mesub-subscription] > [data-mesub-action]) {
2704
+ min-block-size: 48px;
2705
+ border-color: transparent;
2706
+ border-radius: var(--_radius-lg);
2707
+ background: var(--_sunk);
2708
+ color: var(--_text);
2709
+ font-size: 14px;
2710
+ }
2711
+ :is([data-mesub-step="subscription"] > [data-mesub-action], [data-mesub-subscription] > [data-mesub-action]):hover:not(:disabled) {
2712
+ background: color-mix(in srgb, var(--_text) 9%, var(--_bg));
2713
+ }
2714
+ :is([data-mesub-step="subscription"] > [data-mesub-action], [data-mesub-subscription] > [data-mesub-action]):active:not(:disabled) {
2715
+ border-color: transparent;
2716
+ }
2717
+ /* under a filled action, Done is the checkout's text button */
2718
+ [data-mesub-step="subscription"] > [data-mesub-action] + [data-mesub-cancel] {
2719
+ margin-block-start: -8px;
2720
+ }
2721
+
2722
+ /* what Pay now came to: a centred line, as "Nothing was charged." on the checkout */
2723
+ [data-mesub-pay-now-said] {
2724
+ position: relative;
2725
+ justify-self: center;
2726
+ margin: 0;
2727
+ color: var(--_text-soft);
2728
+ font-size: 13px;
2729
+ line-height: 18px;
2730
+ text-align: center;
2731
+ text-wrap: pretty;
2732
+ }
2733
+ [data-mesub-pay-now-said="sent"] {
2734
+ padding-inline-start: 18px;
2735
+ color: var(--_success-text);
2736
+ }
2737
+ [data-mesub-pay-now-said="sent"]::before {
2738
+ content: "";
2739
+ position: absolute;
2740
+ inset-inline-start: 2px;
2741
+ inset-block-start: 4px;
2742
+ inline-size: 9px;
2743
+ block-size: 5px;
2744
+ border-inline-start: 1.5px solid currentColor;
2745
+ border-block-end: 1.5px solid currentColor;
2746
+ transform: rotate(-45deg);
2747
+ }
2748
+ [data-mesub-pay-now-said="refused"] {
2749
+ color: var(--_danger-text);
2750
+ }
2751
+ [data-mesub-pay-now-said="wait"] {
2752
+ color: var(--_text-soft);
2753
+ }
2754
+
2755
+ /* the list in a page: one card per subscription, at the checkout window's width */
2756
+ [data-mesub-subscription-list] {
2757
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
2758
+ align-items: start;
2759
+ }
2760
+ [data-mesub-subscription] {
2761
+ gap: 14px;
2762
+ padding: 20px;
2763
+ border-radius: calc(var(--_radius-lg) + 4px);
2764
+ }