@quantaroute/checkout 1.1.1 → 1.2.1

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.
@@ -0,0 +1,1082 @@
1
+ /* ============================================================
2
+ QuantaRoute Checkout Widget — Complete Stylesheet
3
+ Mobile-first · Desktop responsive · Light & Dark themes
4
+ ============================================================ */
5
+
6
+ /* ── Design tokens ───────────────────────────────────────── */
7
+ .qr-checkout {
8
+ --qr-primary: #0ea5e9;
9
+ --qr-primary-dark: #0284c7;
10
+ --qr-primary-light: #e0f2fe;
11
+ --qr-success: #10b981;
12
+ --qr-warning: #f59e0b;
13
+ --qr-error: #ef4444;
14
+ --qr-text: #1e293b;
15
+ --qr-text-muted: #64748b;
16
+ --qr-text-faint: #94a3b8;
17
+ --qr-bg: #ffffff;
18
+ --qr-bg-subtle: #f8fafc;
19
+ --qr-border: #e2e8f0;
20
+ --qr-border-focus: #0ea5e9;
21
+ --qr-radius-sm: 8px;
22
+ --qr-radius: 12px;
23
+ --qr-radius-lg: 16px;
24
+ --qr-shadow: 0 2px 16px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.04);
25
+ --qr-shadow-card: 0 4px 32px rgba(0,0,0,.12);
26
+ --qr-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
27
+ 'Helvetica Neue', Arial, sans-serif;
28
+ --qr-transition: 150ms ease;
29
+ }
30
+
31
+ /* Dark theme overrides */
32
+ .qr-checkout--dark {
33
+ --qr-text: #f1f5f9;
34
+ --qr-text-muted: #94a3b8;
35
+ --qr-text-faint: #64748b;
36
+ --qr-bg: #1e293b;
37
+ --qr-bg-subtle: #0f172a;
38
+ --qr-border: #334155;
39
+ }
40
+
41
+ /* ── Root container ──────────────────────────────────────── */
42
+ .qr-checkout {
43
+ font-family: var(--qr-font);
44
+ font-size: 14px;
45
+ color: var(--qr-text);
46
+ background: var(--qr-bg);
47
+ border-radius: var(--qr-radius-lg);
48
+ box-shadow: var(--qr-shadow-card);
49
+ overflow: hidden;
50
+ width: 100%;
51
+ max-width: 480px;
52
+ margin: 0 auto;
53
+ display: flex;
54
+ flex-direction: column;
55
+ /* Prevent content bleed */
56
+ isolation: isolate;
57
+ }
58
+
59
+ /* ── Widget header ───────────────────────────────────────── */
60
+ .qr-header {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ padding: 14px 16px 12px;
65
+ border-bottom: 1px solid var(--qr-border);
66
+ background: var(--qr-bg);
67
+ }
68
+
69
+ .qr-header__brand {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 8px;
73
+ }
74
+
75
+ .qr-header__logo {
76
+ width: 20px;
77
+ height: 20px;
78
+ color: var(--qr-primary);
79
+ flex-shrink: 0;
80
+ }
81
+
82
+ .qr-header__title {
83
+ font-size: 15px;
84
+ font-weight: 600;
85
+ color: var(--qr-text);
86
+ letter-spacing: -0.01em;
87
+ }
88
+
89
+ /* ── Progress dots ───────────────────────────────────────── */
90
+ .qr-progress {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 4px;
94
+ }
95
+
96
+ .qr-progress__dot {
97
+ width: 8px;
98
+ height: 8px;
99
+ border-radius: 50%;
100
+ background: var(--qr-border);
101
+ transition: background var(--qr-transition), transform var(--qr-transition);
102
+ }
103
+
104
+ .qr-progress__dot--active {
105
+ background: var(--qr-primary);
106
+ transform: scale(1.1);
107
+ }
108
+
109
+ .qr-progress__line {
110
+ width: 20px;
111
+ height: 2px;
112
+ border-radius: 1px;
113
+ background: var(--qr-border);
114
+ transition: background var(--qr-transition);
115
+ }
116
+
117
+ .qr-progress__line--active {
118
+ background: var(--qr-primary);
119
+ }
120
+
121
+ /* ── Shared step header ──────────────────────────────────── */
122
+ .qr-step-header {
123
+ display: flex;
124
+ align-items: flex-start;
125
+ gap: 10px;
126
+ padding: 14px 16px 12px;
127
+ border-bottom: 1px solid var(--qr-border);
128
+ }
129
+
130
+ .qr-step-badge {
131
+ flex-shrink: 0;
132
+ width: 26px;
133
+ height: 26px;
134
+ border-radius: 50%;
135
+ background: var(--qr-primary);
136
+ color: #fff;
137
+ font-size: 12px;
138
+ font-weight: 700;
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: center;
142
+ margin-top: 1px;
143
+ }
144
+
145
+ .qr-step-text {
146
+ display: flex;
147
+ flex-direction: column;
148
+ gap: 2px;
149
+ min-width: 0;
150
+ }
151
+
152
+ .qr-step-title {
153
+ font-size: 14px;
154
+ font-weight: 600;
155
+ color: var(--qr-text);
156
+ line-height: 1.3;
157
+ }
158
+
159
+ .qr-step-sub {
160
+ font-size: 12px;
161
+ color: var(--qr-text-muted);
162
+ line-height: 1.4;
163
+ }
164
+
165
+ .qr-back-btn {
166
+ flex-shrink: 0;
167
+ width: 34px;
168
+ height: 34px;
169
+ border-radius: var(--qr-radius-sm);
170
+ border: 1px solid var(--qr-border);
171
+ background: transparent;
172
+ color: var(--qr-text);
173
+ cursor: pointer;
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: center;
177
+ transition: background var(--qr-transition), border-color var(--qr-transition);
178
+ margin-top: -4px;
179
+ }
180
+
181
+ .qr-back-btn:hover {
182
+ background: var(--qr-bg-subtle);
183
+ border-color: var(--qr-primary);
184
+ }
185
+
186
+ .qr-back-btn svg {
187
+ width: 16px;
188
+ height: 16px;
189
+ }
190
+
191
+ /* ── Map area ────────────────────────────────────────────── */
192
+ .qr-map-wrapper {
193
+ display: flex;
194
+ flex-direction: column;
195
+ }
196
+
197
+ .qr-map-outer {
198
+ position: relative;
199
+ overflow: hidden;
200
+ background: #e8ecf0;
201
+ /* Height is set inline via mapHeight prop */
202
+ }
203
+
204
+ .qr-map-canvas {
205
+ position: absolute;
206
+ inset: 0;
207
+ width: 100%;
208
+ height: 100%;
209
+ }
210
+
211
+ /* Hide MapLibre's default navigation on small screens */
212
+ @media (max-width: 380px) {
213
+ .maplibregl-ctrl-top-right {
214
+ display: none;
215
+ }
216
+ /* When zoom controls are hidden, position locate button at top-right */
217
+ .qr-locate-btn {
218
+ top: 10px;
219
+ right: 10px;
220
+ }
221
+ .qr-geo-error {
222
+ top: 52px; /* Below locate button when zoom controls are hidden (10px + 34px + 8px gap) */
223
+ }
224
+ }
225
+
226
+ /* ── Custom pin marker ───────────────────────────────────── */
227
+
228
+ /*
229
+ * PIN SIZING CONTRACT
230
+ * ───────────────────
231
+ * These MUST match the inline width/height set on the element in JS
232
+ * (createPinElement sets el.style.width = '40px'; el.style.height = '52px').
233
+ *
234
+ * MapLibre reads offsetWidth / offsetHeight to compute the `anchor:'bottom'`
235
+ * translation. If the CSS dimensions differ from the SVG dimensions the pin
236
+ * tip will land at the wrong pixel.
237
+ *
238
+ * Pin tip is at SVG coordinate (20, 52) = bottom-center of 40×52 element.
239
+ */
240
+ .qr-pin {
241
+ width: 40px;
242
+ height: 52px;
243
+ position: relative;
244
+ cursor: grab;
245
+ user-select: none;
246
+ -webkit-user-select: none;
247
+ /* Let the pulse ring render outside the pin box */
248
+ overflow: visible;
249
+ }
250
+
251
+ .qr-pin:active {
252
+ cursor: grabbing;
253
+ }
254
+
255
+ .qr-pin__svg {
256
+ /*
257
+ * display:block is REQUIRED.
258
+ * Inline-level <svg> elements get bottom-aligned to the text baseline,
259
+ * which adds ~3-5 px of descender whitespace below the element.
260
+ * That whitespace makes .qr-pin taller than 52px, shifting the anchor.
261
+ */
262
+ display: block;
263
+ width: 40px;
264
+ height: 52px;
265
+ transition: transform 120ms ease;
266
+ }
267
+
268
+ .qr-pin:active .qr-pin__svg {
269
+ transform: scale(1.1) translateY(-4px);
270
+ }
271
+
272
+ /*
273
+ * PULSE RING
274
+ * ──────────
275
+ * We want the 20×20 px circle centred exactly at the pin TIP (y = 52px from top).
276
+ *
277
+ * bottom: -(height / 2) = -(20 / 2) = -10px
278
+ *
279
+ * Derivation:
280
+ * CSS `bottom: X` places the element's BOTTOM EDGE X px from the container
281
+ * bottom. We want the element's CENTRE at the container bottom (pin tip):
282
+ *
283
+ * bottom_edge = bottom_tip − element_height + X
284
+ * centre = bottom_edge + element_height/2
285
+ * = bottom_tip − element_height + X + element_height/2
286
+ * = bottom_tip + X − element_height/2
287
+ *
288
+ * Set centre = bottom_tip → X = element_height/2 = 10px
289
+ * But CSS positive `bottom` moves element UP; we want it DOWN → bottom: -10px ✓
290
+ */
291
+ .qr-pin__pulse {
292
+ position: absolute;
293
+ bottom: -10px; /* centres 20px circle at y = PIN_H = 52px (pin tip) */
294
+ left: 50%;
295
+ transform: translateX(-50%);
296
+ width: 20px;
297
+ height: 20px;
298
+ border-radius: 50%;
299
+ background: var(--qr-primary);
300
+ opacity: 0;
301
+ animation: qr-pulse 2.5s ease-out infinite;
302
+ pointer-events: none;
303
+ }
304
+
305
+ @keyframes qr-pulse {
306
+ 0% { transform: translateX(-50%) scale(0.5); opacity: 0.5; }
307
+ 100% { transform: translateX(-50%) scale(2.2); opacity: 0; }
308
+ }
309
+
310
+ /* ── DigiPin overlay badge ───────────────────────────────── */
311
+ .qr-digipin-badge {
312
+ position: absolute;
313
+ top: 10px;
314
+ left: 10px;
315
+ z-index: 10;
316
+ display: flex;
317
+ align-items: center;
318
+ gap: 6px;
319
+ background: var(--qr-bg);
320
+ border: 1.5px solid var(--qr-primary-light);
321
+ border-radius: 100px;
322
+ padding: 5px 12px 5px 8px;
323
+ box-shadow: 0 2px 8px rgba(0,0,0,.12);
324
+ animation: qr-fade-in 200ms ease;
325
+ max-width: calc(100% - 60px);
326
+ }
327
+
328
+ .qr-digipin-badge__label {
329
+ font-size: 10px;
330
+ font-weight: 700;
331
+ text-transform: uppercase;
332
+ letter-spacing: 0.06em;
333
+ color: var(--qr-text-muted);
334
+ white-space: nowrap;
335
+ }
336
+
337
+ .qr-digipin-badge__code {
338
+ font-size: 13px;
339
+ font-weight: 700;
340
+ color: var(--qr-primary);
341
+ letter-spacing: 0.03em;
342
+ font-family: 'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', monospace;
343
+ white-space: nowrap;
344
+ }
345
+
346
+ /* Inline variant (used in success screen) */
347
+ .qr-digipin-badge--inline {
348
+ position: static;
349
+ display: inline-flex;
350
+ }
351
+
352
+ /* ── Out-of-India notice ─────────────────────────────────── */
353
+ .qr-map-notice {
354
+ position: absolute;
355
+ bottom: 12px;
356
+ left: 50%;
357
+ transform: translateX(-50%);
358
+ background: rgba(30,41,59,.85);
359
+ color: #fff;
360
+ font-size: 12px;
361
+ font-weight: 500;
362
+ padding: 6px 14px;
363
+ border-radius: 100px;
364
+ white-space: nowrap;
365
+ backdrop-filter: blur(4px);
366
+ pointer-events: none;
367
+ }
368
+
369
+ /* ── Locate-me button ────────────────────────────────────── */
370
+ .qr-locate-btn {
371
+ position: absolute;
372
+ top: 72px; /* Positioned below MapLibre's NavigationControl (zoom buttons: ~30px each + gap) */
373
+ right: 12px; /* Align with MapLibre controls (they use 10px right margin) */
374
+ z-index: 10;
375
+ width: 24px; /* Match MapLibre's control button width */
376
+ height: 24px; /* Match MapLibre's control button height */
377
+ border-radius: 4px; /* Match MapLibre's control button border radius */
378
+ background: var(--qr-bg);
379
+ border: 1px solid var(--qr-border);
380
+ color: var(--qr-text);
381
+ cursor: pointer;
382
+ display: flex;
383
+ align-items: center;
384
+ justify-content: center;
385
+ box-shadow: 0 0 0 1px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.1);
386
+ transition: background var(--qr-transition), border-color var(--qr-transition), transform 80ms;
387
+ touch-action: manipulation;
388
+ }
389
+
390
+ .qr-locate-btn:hover:not(:disabled) {
391
+ background: var(--qr-primary-light);
392
+ border-color: var(--qr-primary);
393
+ color: var(--qr-primary);
394
+ }
395
+
396
+ .qr-locate-btn:active:not(:disabled) {
397
+ transform: scale(0.94);
398
+ }
399
+
400
+ .qr-locate-btn:disabled {
401
+ opacity: 0.6;
402
+ cursor: not-allowed;
403
+ }
404
+
405
+ .qr-locate-btn svg {
406
+ width: 16px;
407
+ height: 16px;
408
+ flex-shrink: 0; /* Prevent icon from shrinking */
409
+ }
410
+
411
+ .qr-locate-btn__label {
412
+ font-size: 13px;
413
+ font-weight: 500;
414
+ line-height: 1;
415
+ }
416
+
417
+ /* Hide text label on very small screens to save space */
418
+ @media (max-width: 360px) {
419
+ .qr-locate-btn__label {
420
+ display: none;
421
+ }
422
+ .qr-locate-btn {
423
+ width: 34px;
424
+ padding: 0;
425
+ }
426
+ }
427
+
428
+ .qr-locate-btn--loading {
429
+ cursor: wait;
430
+ }
431
+
432
+ /* ── Geo error toast ─────────────────────────────────────── */
433
+ .qr-geo-error {
434
+ position: absolute;
435
+ top: 132px; /* Positioned below locate button (72px + 34px + 8px gap) */
436
+ right: 10px;
437
+ left: 10px;
438
+ z-index: 20;
439
+ background: #fff;
440
+ border: 1.5px solid var(--qr-error);
441
+ border-radius: var(--qr-radius-sm);
442
+ padding: 8px 12px;
443
+ font-size: 12px;
444
+ color: var(--qr-error);
445
+ display: flex;
446
+ align-items: flex-start;
447
+ gap: 8px;
448
+ box-shadow: 0 4px 12px rgba(0,0,0,.1);
449
+ animation: qr-slide-up 200ms ease;
450
+ }
451
+
452
+ .qr-geo-error__dismiss {
453
+ flex-shrink: 0;
454
+ background: none;
455
+ border: none;
456
+ cursor: pointer;
457
+ color: var(--qr-error);
458
+ font-size: 16px;
459
+ line-height: 1;
460
+ padding: 0;
461
+ margin-left: auto;
462
+ opacity: 0.8;
463
+ }
464
+
465
+ .qr-geo-error__dismiss:hover {
466
+ opacity: 1;
467
+ }
468
+
469
+ /* ── Coordinates strip ───────────────────────────────────── */
470
+ .qr-coords-strip {
471
+ padding: 6px 16px;
472
+ font-size: 11px;
473
+ color: var(--qr-text-faint);
474
+ display: flex;
475
+ align-items: center;
476
+ gap: 4px;
477
+ background: var(--qr-bg-subtle);
478
+ border-bottom: 1px solid var(--qr-border);
479
+ font-family: 'SF Mono', 'Fira Code', monospace;
480
+ }
481
+
482
+ .qr-coords-sep {
483
+ opacity: 0.4;
484
+ }
485
+
486
+ /* ── Map action bar ──────────────────────────────────────── */
487
+ .qr-map-actions {
488
+ padding: 12px 16px;
489
+ display: flex;
490
+ flex-direction: column;
491
+ gap: 6px;
492
+ background: var(--qr-bg);
493
+ }
494
+
495
+ .qr-map-hint {
496
+ text-align: center;
497
+ font-size: 11px;
498
+ color: var(--qr-text-muted);
499
+ margin: 0;
500
+ }
501
+
502
+ /* ── Form wrapper ────────────────────────────────────────── */
503
+ .qr-form-wrapper {
504
+ display: flex;
505
+ flex-direction: column;
506
+ overflow-y: auto;
507
+ max-height: 85vh;
508
+ -webkit-overflow-scrolling: touch;
509
+ }
510
+
511
+ /* DigiPin reference strip at top of form */
512
+ .qr-form-digipin-strip {
513
+ display: flex;
514
+ align-items: center;
515
+ gap: 8px;
516
+ padding: 10px 16px;
517
+ background: var(--qr-primary-light);
518
+ border-bottom: 1px solid rgba(14,165,233,.2);
519
+ font-size: 12px;
520
+ }
521
+
522
+ .qr-checkout--dark .qr-form-digipin-strip {
523
+ background: rgba(14,165,233,.12);
524
+ }
525
+
526
+ .qr-form-digipin-strip svg {
527
+ width: 14px;
528
+ height: 14px;
529
+ color: var(--qr-primary);
530
+ flex-shrink: 0;
531
+ }
532
+
533
+ .qr-form-digipin-strip__label {
534
+ font-size: 10px;
535
+ font-weight: 700;
536
+ text-transform: uppercase;
537
+ letter-spacing: 0.06em;
538
+ color: var(--qr-text-muted);
539
+ }
540
+
541
+ .qr-form-digipin-strip__code {
542
+ font-size: 13px;
543
+ font-weight: 700;
544
+ color: var(--qr-primary);
545
+ letter-spacing: 0.04em;
546
+ font-family: 'SF Mono', 'Fira Code', monospace;
547
+ }
548
+
549
+ /* ── Loading state ───────────────────────────────────────── */
550
+ .qr-loading-state {
551
+ display: flex;
552
+ flex-direction: column;
553
+ align-items: center;
554
+ justify-content: center;
555
+ gap: 12px;
556
+ padding: 48px 16px;
557
+ }
558
+
559
+ .qr-loading-state__text {
560
+ font-size: 13px;
561
+ color: var(--qr-text-muted);
562
+ margin: 0;
563
+ }
564
+
565
+ /* ── Error state ─────────────────────────────────────────── */
566
+ .qr-error-state {
567
+ display: flex;
568
+ flex-direction: column;
569
+ align-items: center;
570
+ gap: 8px;
571
+ padding: 32px 16px;
572
+ text-align: center;
573
+ }
574
+
575
+ .qr-error-state__icon {
576
+ font-size: 28px;
577
+ color: var(--qr-warning);
578
+ }
579
+
580
+ .qr-error-state__msg {
581
+ font-size: 13px;
582
+ color: var(--qr-text-muted);
583
+ margin: 0;
584
+ max-width: 280px;
585
+ }
586
+
587
+ /* ── Form ────────────────────────────────────────────────── */
588
+ .qr-form {
589
+ display: flex;
590
+ flex-direction: column;
591
+ gap: 0;
592
+ padding-bottom: 8px;
593
+ }
594
+
595
+ /* Fieldsets */
596
+ .qr-fieldset {
597
+ border: none;
598
+ padding: 0;
599
+ margin: 0;
600
+ border-bottom: 1px solid var(--qr-border);
601
+ }
602
+
603
+ .qr-fieldset__legend {
604
+ width: 100%;
605
+ display: flex;
606
+ align-items: center;
607
+ gap: 8px;
608
+ padding: 12px 16px 10px;
609
+ font-size: 12px;
610
+ font-weight: 600;
611
+ color: var(--qr-text-muted);
612
+ text-transform: uppercase;
613
+ letter-spacing: 0.06em;
614
+ }
615
+
616
+ .qr-fieldset__icon {
617
+ font-size: 14px;
618
+ }
619
+
620
+ /* ── Auto-filled grid ────────────────────────────────────── */
621
+ .qr-auto-grid {
622
+ display: grid;
623
+ grid-template-columns: 1fr 1fr;
624
+ gap: 0;
625
+ padding: 0 8px 12px;
626
+ }
627
+
628
+ .qr-auto-row {
629
+ display: flex;
630
+ flex-direction: column;
631
+ gap: 2px;
632
+ padding: 8px;
633
+ border-radius: var(--qr-radius-sm);
634
+ }
635
+
636
+ .qr-auto-row--full {
637
+ grid-column: 1 / -1;
638
+ }
639
+
640
+ .qr-auto-row__label {
641
+ font-size: 10px;
642
+ font-weight: 600;
643
+ text-transform: uppercase;
644
+ letter-spacing: 0.05em;
645
+ color: var(--qr-text-faint);
646
+ }
647
+
648
+ .qr-auto-row__value {
649
+ font-size: 13px;
650
+ font-weight: 500;
651
+ color: var(--qr-text);
652
+ }
653
+
654
+ .qr-auto-row__value--pin {
655
+ font-family: 'SF Mono', 'Fira Code', monospace;
656
+ font-size: 14px;
657
+ font-weight: 700;
658
+ color: var(--qr-primary);
659
+ }
660
+
661
+ /* Locality select dropdown */
662
+ .qr-auto-row__select {
663
+ width: 100%;
664
+ padding: 6px 10px;
665
+ font-size: 13px;
666
+ font-weight: 500;
667
+ font-family: var(--qr-font);
668
+ color: var(--qr-text);
669
+ background: var(--qr-bg);
670
+ border: 1.5px solid var(--qr-border);
671
+ border-radius: var(--qr-radius-sm);
672
+ outline: none;
673
+ cursor: pointer;
674
+ transition: border-color var(--qr-transition), box-shadow var(--qr-transition);
675
+ -webkit-appearance: none;
676
+ appearance: none;
677
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%2364748b' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
678
+ background-repeat: no-repeat;
679
+ background-position: right 8px center;
680
+ padding-right: 32px;
681
+ }
682
+
683
+ .qr-auto-row__select:hover {
684
+ border-color: var(--qr-primary);
685
+ }
686
+
687
+ .qr-auto-row__select:focus {
688
+ border-color: var(--qr-primary);
689
+ box-shadow: 0 0 0 3px rgba(14,165,233,.15);
690
+ }
691
+
692
+ .qr-auto-row__select:focus-visible {
693
+ outline: 2px solid var(--qr-primary);
694
+ outline-offset: 2px;
695
+ }
696
+
697
+ /* ── Manual fields grid ──────────────────────────────────── */
698
+ .qr-fields-grid {
699
+ display: grid;
700
+ grid-template-columns: 1fr 1fr;
701
+ gap: 0 8px;
702
+ padding: 8px 16px 16px;
703
+ }
704
+
705
+ .qr-field {
706
+ display: flex;
707
+ flex-direction: column;
708
+ gap: 4px;
709
+ padding-top: 8px;
710
+ }
711
+
712
+ .qr-field--full {
713
+ grid-column: 1 / -1;
714
+ }
715
+
716
+ .qr-field__label {
717
+ font-size: 12px;
718
+ font-weight: 600;
719
+ color: var(--qr-text-muted);
720
+ display: flex;
721
+ align-items: center;
722
+ gap: 5px;
723
+ }
724
+
725
+ .qr-required {
726
+ color: var(--qr-error);
727
+ font-size: 14px;
728
+ line-height: 1;
729
+ }
730
+
731
+ .qr-optional {
732
+ font-size: 10px;
733
+ font-weight: 400;
734
+ color: var(--qr-text-faint);
735
+ text-transform: lowercase;
736
+ letter-spacing: 0;
737
+ }
738
+
739
+ .qr-field__input {
740
+ width: 100%;
741
+ padding: 9px 11px;
742
+ font-size: 14px;
743
+ font-family: var(--qr-font);
744
+ color: var(--qr-text);
745
+ background: var(--qr-bg);
746
+ border: 1.5px solid var(--qr-border);
747
+ border-radius: var(--qr-radius-sm);
748
+ outline: none;
749
+ transition: border-color var(--qr-transition), box-shadow var(--qr-transition);
750
+ -webkit-appearance: none;
751
+ appearance: none;
752
+ box-sizing: border-box;
753
+ }
754
+
755
+ .qr-field__input::placeholder {
756
+ color: var(--qr-text-faint);
757
+ }
758
+
759
+ .qr-field__input:focus {
760
+ border-color: var(--qr-primary);
761
+ box-shadow: 0 0 0 3px rgba(14,165,233,.15);
762
+ }
763
+
764
+ .qr-field__input:focus-visible {
765
+ outline: 2px solid var(--qr-primary);
766
+ outline-offset: 2px;
767
+ }
768
+
769
+ /* ── Delivery chip ───────────────────────────────────────── */
770
+ .qr-delivery-chip {
771
+ font-size: 10px;
772
+ font-weight: 600;
773
+ padding: 2px 8px;
774
+ border-radius: 100px;
775
+ margin-left: auto;
776
+ }
777
+
778
+ .qr-delivery-chip--yes {
779
+ background: rgba(16,185,129,.12);
780
+ color: #059669;
781
+ }
782
+
783
+ .qr-delivery-chip--no {
784
+ background: rgba(239,68,68,.1);
785
+ color: #dc2626;
786
+ }
787
+
788
+ /* ── Form actions ────────────────────────────────────────── */
789
+ .qr-form-actions {
790
+ display: flex;
791
+ gap: 8px;
792
+ padding: 12px 16px;
793
+ border-top: 1px solid var(--qr-border);
794
+ background: var(--qr-bg);
795
+ }
796
+
797
+ /* ── Buttons ─────────────────────────────────────────────── */
798
+ .qr-btn {
799
+ display: inline-flex;
800
+ align-items: center;
801
+ justify-content: center;
802
+ gap: 6px;
803
+ padding: 10px 18px;
804
+ font-family: var(--qr-font);
805
+ font-size: 14px;
806
+ font-weight: 600;
807
+ border-radius: var(--qr-radius-sm);
808
+ border: none;
809
+ cursor: pointer;
810
+ transition:
811
+ background var(--qr-transition),
812
+ color var(--qr-transition),
813
+ border-color var(--qr-transition),
814
+ transform 80ms,
815
+ box-shadow var(--qr-transition);
816
+ white-space: nowrap;
817
+ user-select: none;
818
+ -webkit-tap-highlight-color: transparent;
819
+ touch-action: manipulation;
820
+ /* Minimum touch target */
821
+ min-height: 44px;
822
+ }
823
+
824
+ .qr-btn:active:not(:disabled) {
825
+ transform: scale(0.97);
826
+ }
827
+
828
+ .qr-btn:disabled {
829
+ opacity: 0.45;
830
+ cursor: not-allowed;
831
+ }
832
+
833
+ .qr-btn svg {
834
+ width: 16px;
835
+ height: 16px;
836
+ flex-shrink: 0;
837
+ }
838
+
839
+ /* Primary */
840
+ .qr-btn--primary {
841
+ background: var(--qr-primary);
842
+ color: #fff;
843
+ box-shadow: 0 1px 4px rgba(14,165,233,.3);
844
+ }
845
+
846
+ .qr-btn--primary:hover:not(:disabled) {
847
+ background: var(--qr-primary-dark);
848
+ box-shadow: 0 4px 12px rgba(14,165,233,.4);
849
+ }
850
+
851
+ /* Secondary */
852
+ .qr-btn--secondary {
853
+ background: var(--qr-bg-subtle);
854
+ color: var(--qr-text);
855
+ border: 1.5px solid var(--qr-border);
856
+ }
857
+
858
+ .qr-btn--secondary:hover:not(:disabled) {
859
+ background: var(--qr-border);
860
+ }
861
+
862
+ /* Ghost */
863
+ .qr-btn--ghost {
864
+ background: transparent;
865
+ color: var(--qr-text-muted);
866
+ border: 1.5px solid var(--qr-border);
867
+ }
868
+
869
+ .qr-btn--ghost:hover:not(:disabled) {
870
+ background: var(--qr-bg-subtle);
871
+ color: var(--qr-text);
872
+ }
873
+
874
+ /* Full width */
875
+ .qr-btn--full {
876
+ width: 100%;
877
+ }
878
+
879
+ /* Grow to fill */
880
+ .qr-btn--grow {
881
+ flex: 1;
882
+ }
883
+
884
+ /* Small */
885
+ .qr-btn--sm {
886
+ font-size: 12px;
887
+ padding: 7px 14px;
888
+ min-height: 36px;
889
+ }
890
+
891
+ /* ── Spinner ─────────────────────────────────────────────── */
892
+ .qr-spinner {
893
+ display: inline-block;
894
+ width: 16px;
895
+ height: 16px;
896
+ border: 2px solid rgba(255,255,255,.3);
897
+ border-top-color: currentColor;
898
+ border-radius: 50%;
899
+ animation: qr-spin 0.6s linear infinite;
900
+ flex-shrink: 0;
901
+ }
902
+
903
+ .qr-spinner--lg {
904
+ width: 32px;
905
+ height: 32px;
906
+ border-width: 3px;
907
+ border-color: var(--qr-border);
908
+ border-top-color: var(--qr-primary);
909
+ }
910
+
911
+ .qr-spinner--sm {
912
+ width: 13px;
913
+ height: 13px;
914
+ border-width: 2px;
915
+ }
916
+
917
+ @keyframes qr-spin {
918
+ to { transform: rotate(360deg); }
919
+ }
920
+
921
+ /* ── Success screen ──────────────────────────────────────── */
922
+ .qr-success {
923
+ display: flex;
924
+ flex-direction: column;
925
+ align-items: center;
926
+ gap: 12px;
927
+ padding: 32px 20px 24px;
928
+ text-align: center;
929
+ animation: qr-fade-in 300ms ease;
930
+ }
931
+
932
+ .qr-success__icon {
933
+ width: 56px;
934
+ height: 56px;
935
+ }
936
+
937
+ .qr-success__icon svg {
938
+ width: 100%;
939
+ height: 100%;
940
+ }
941
+
942
+ .qr-success__title {
943
+ font-size: 18px;
944
+ font-weight: 700;
945
+ color: var(--qr-text);
946
+ margin: 0;
947
+ letter-spacing: -0.01em;
948
+ }
949
+
950
+ .qr-success__address {
951
+ font-size: 13px;
952
+ color: var(--qr-text-muted);
953
+ margin: 0;
954
+ max-width: 320px;
955
+ line-height: 1.5;
956
+ }
957
+
958
+ .qr-success__meta {
959
+ display: flex;
960
+ align-items: center;
961
+ flex-wrap: wrap;
962
+ gap: 8px;
963
+ justify-content: center;
964
+ }
965
+
966
+ /* ── Widget footer ───────────────────────────────────────── */
967
+ .qr-footer {
968
+ display: flex;
969
+ align-items: center;
970
+ justify-content: center;
971
+ gap: 4px;
972
+ padding: 8px 16px;
973
+ font-size: 11px;
974
+ color: var(--qr-text-faint);
975
+ border-top: 1px solid var(--qr-border);
976
+ background: var(--qr-bg-subtle);
977
+ }
978
+
979
+ .qr-footer__link {
980
+ color: var(--qr-primary);
981
+ text-decoration: none;
982
+ font-weight: 500;
983
+ }
984
+
985
+ .qr-footer__link:hover {
986
+ text-decoration: underline;
987
+ }
988
+
989
+ .qr-footer__flag {
990
+ font-size: 12px;
991
+ }
992
+
993
+ /* ── Animations ──────────────────────────────────────────── */
994
+ @keyframes qr-fade-in {
995
+ from { opacity: 0; transform: translateY(4px); }
996
+ to { opacity: 1; transform: translateY(0); }
997
+ }
998
+
999
+ @keyframes qr-slide-up {
1000
+ from { opacity: 0; transform: translateY(8px); }
1001
+ to { opacity: 1; transform: translateY(0); }
1002
+ }
1003
+
1004
+ /* ── Mobile overrides (≤ 480px) ─────────────────────────── */
1005
+ @media (max-width: 480px) {
1006
+ .qr-checkout {
1007
+ border-radius: 0;
1008
+ max-width: 100%;
1009
+ box-shadow: none;
1010
+ min-height: 100dvh;
1011
+ }
1012
+
1013
+ .qr-form-wrapper {
1014
+ max-height: none;
1015
+ overflow-y: visible;
1016
+ }
1017
+
1018
+ .qr-fields-grid {
1019
+ grid-template-columns: 1fr;
1020
+ }
1021
+
1022
+ .qr-auto-grid {
1023
+ grid-template-columns: 1fr 1fr;
1024
+ }
1025
+
1026
+ .qr-map-actions {
1027
+ position: sticky;
1028
+ bottom: 0;
1029
+ background: var(--qr-bg);
1030
+ border-top: 1px solid var(--qr-border);
1031
+ padding: 12px 16px env(safe-area-inset-bottom, 12px);
1032
+ z-index: 20;
1033
+ }
1034
+
1035
+ .qr-form-actions {
1036
+ position: sticky;
1037
+ bottom: 0;
1038
+ background: var(--qr-bg);
1039
+ padding: 12px 16px env(safe-area-inset-bottom, 12px);
1040
+ z-index: 20;
1041
+ }
1042
+
1043
+ .qr-btn {
1044
+ font-size: 15px;
1045
+ min-height: 48px;
1046
+ }
1047
+ }
1048
+
1049
+ /* ── Tablet / Desktop (> 480px) ──────────────────────────── */
1050
+ @media (min-width: 481px) {
1051
+ .qr-checkout {
1052
+ border-radius: var(--qr-radius-lg);
1053
+ }
1054
+
1055
+ .qr-fields-grid {
1056
+ grid-template-columns: 1fr 1fr;
1057
+ }
1058
+ }
1059
+
1060
+ /* ── High-contrast / reduced-motion ─────────────────────── */
1061
+ @media (prefers-reduced-motion: reduce) {
1062
+ .qr-pin__pulse,
1063
+ .qr-spinner {
1064
+ animation: none;
1065
+ }
1066
+
1067
+ .qr-btn,
1068
+ .qr-locate-btn,
1069
+ .qr-field__input,
1070
+ .qr-progress__dot,
1071
+ .qr-progress__line {
1072
+ transition: none;
1073
+ }
1074
+ }
1075
+
1076
+ /* ── Focus visible (keyboard nav) ────────────────────────── */
1077
+ .qr-btn:focus-visible,
1078
+ .qr-back-btn:focus-visible,
1079
+ .qr-locate-btn:focus-visible {
1080
+ outline: 2px solid var(--qr-primary);
1081
+ outline-offset: 2px;
1082
+ }