@code-collective/booking-widget 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +266 -0
  2. package/dist/booking-widget.css +2 -0
  3. package/dist/booking-widget.js +4359 -0
  4. package/dist/booking-widget.umd.cjs +2 -0
  5. package/package.json +48 -0
  6. package/src/lib/AvailabilityCalendar.svelte +222 -0
  7. package/src/lib/CartBar.svelte +32 -0
  8. package/src/lib/CartBarView.svelte +60 -0
  9. package/src/lib/CartOverview.svelte +20 -0
  10. package/src/lib/CartOverviewButton.svelte +120 -0
  11. package/src/lib/Checkout.svelte +55 -0
  12. package/src/lib/CheckoutModal.svelte +510 -0
  13. package/src/lib/ConsentSection.svelte +45 -0
  14. package/src/lib/ContactForm.svelte +67 -0
  15. package/src/lib/CountdownTimer.svelte +30 -0
  16. package/src/lib/EditBookingView.svelte +73 -0
  17. package/src/lib/OptionCard.svelte +41 -0
  18. package/src/lib/PaymentPage.svelte +155 -0
  19. package/src/lib/PickupPointPicker.svelte +76 -0
  20. package/src/lib/ResultView.svelte +84 -0
  21. package/src/lib/SelectableCard.svelte +71 -0
  22. package/src/lib/TicketConfigurator.svelte +78 -0
  23. package/src/lib/TimeSlotPicker.svelte +45 -0
  24. package/src/lib/UnitCounter.svelte +91 -0
  25. package/src/lib/WizardPage.svelte +561 -0
  26. package/src/lib/api.ts +204 -0
  27. package/src/lib/app.css +246 -0
  28. package/src/lib/cart-manager.ts +76 -0
  29. package/src/lib/client-types.ts +52 -0
  30. package/src/lib/config.ts +92 -0
  31. package/src/lib/currency.ts +18 -0
  32. package/src/lib/elements/bw-cart.svelte +44 -0
  33. package/src/lib/elements/bw-checkout.svelte +99 -0
  34. package/src/lib/elements/bw-configurator.svelte +66 -0
  35. package/src/lib/elements/env.ts +11 -0
  36. package/src/lib/elements/register.ts +149 -0
  37. package/src/lib/elements/shared.ts +14 -0
  38. package/src/lib/elements/theme.css +193 -0
  39. package/src/lib/fake-api.ts +282 -0
  40. package/src/lib/generated-types.ts +828 -0
  41. package/src/lib/index.ts +189 -0
  42. package/src/lib/messages.ts +3 -0
  43. package/src/lib/mock-data.ts +241 -0
  44. package/src/lib/session-manager.ts +75 -0
  45. package/src/lib/utils.ts +25 -0
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ # Booking Widget
2
+
3
+ A Svelte 5 widget library for embedding ticket sales on tourism websites. Three custom HTML elements handle product selection, cart management, and payment via Peach Payments.
4
+
5
+ ## Option 1: HTML Custom Elements (CDN)
6
+
7
+ Drop in a script tag and use the custom elements directly. No framework or npm install required.
8
+
9
+ ```html
10
+ <head>
11
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@latest/dist/booking-widget.min.css" />
12
+ </head>
13
+ <body>
14
+ <bw-configurator product-id="your-product-id" checkout-key="your-checkout-key"></bw-configurator>
15
+ <bw-cart display="button"></bw-cart>
16
+ <bw-cart display="bar"></bw-cart>
17
+ <bw-checkout></bw-checkout>
18
+
19
+ <script src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@latest/dist/booking-widget.min.js"></script>
20
+ </body>
21
+ ```
22
+
23
+ The script auto-wires the elements together:
24
+ - Adding an item shows the cart and opens the checkout overlay
25
+ - Clicking checkout in the cart opens the overlay
26
+ - Closing or completing checkout closes the overlay
27
+
28
+ ### Element attributes
29
+
30
+ #### `<bw-configurator>`
31
+
32
+ | Attribute | Required | Description |
33
+ |---|---|---|
34
+ | `product-id` | Yes | OCTO product ID |
35
+ | `checkout-key` | Yes | Public key identifying the supplier |
36
+ | `wizard-pages` | No | JSON string for wizard step ordering |
37
+ | `auto-select-single-time-slot` | No | Boolean. Skips time picker if only one slot |
38
+ | `cancelable` | No | Boolean. Shows a cancel button |
39
+ | `no-auto-checkout` | No | Boolean. Prevents auto-opening checkout on add |
40
+ | `on-cart-change` | No | Name of a global JS function to call on add |
41
+
42
+ #### `<bw-cart>`
43
+
44
+ | Attribute | Required | Description |
45
+ |---|---|---|
46
+ | `checkout-key` | Yes | Public key identifying the supplier |
47
+ | `display` | No | `bar` (default) or `button` |
48
+
49
+ #### `<bw-checkout>`
50
+
51
+ | Attribute | Required | Description |
52
+ |---|---|---|
53
+ | `checkout-key` | Yes | Public key identifying the supplier |
54
+ | `wizard-pages` | No | JSON string for wizard step ordering (edit flow) |
55
+
56
+ ### Global options
57
+
58
+ Set `window.bwOptions` before the widget script loads:
59
+
60
+ ```html
61
+ <script>
62
+ window.bwOptions = {
63
+ shouldBottomCloseOnModal: true,
64
+ autoSelectSingleTimeSlot: false,
65
+ wizardPages: '',
66
+ };
67
+ </script>
68
+ <script src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@latest/dist/booking-widget.min.js"></script>
69
+ ```
70
+
71
+ | Option | Default | Description |
72
+ |---|---|---|
73
+ | `shouldBottomCloseOnModal` | `true` | Hide bar carts when checkout modal opens |
74
+ | `autoSelectSingleTimeSlot` | `false` | Auto-select when only one time slot |
75
+ | `wizardPages` | `''` | JSON wizard step ordering for all elements |
76
+
77
+ ### Window events
78
+
79
+ All `bw:*` events are re-dispatched on `window`:
80
+
81
+ ```js
82
+ window.addEventListener('bw:order-confirmed', (e) => {
83
+ console.log(e.detail); // { cartToken, value, currency }
84
+ });
85
+ ```
86
+
87
+ | Event | Detail | When |
88
+ |---|---|---|
89
+ | `bw:cart-change` | `{ itemCount, cartItemId, totalFormatted }` | Item added to cart |
90
+ | `bw:order-confirmed` | `{ cartToken, value, currency }` | Payment completed |
91
+ | `bw:modal-open` | -- | Checkout modal opens |
92
+ | `bw:modal-close` | -- | Checkout modal closes |
93
+ | `bw:checkout` | -- | Cart checkout button clicked |
94
+ | `bw:close` | -- | Checkout dismissed |
95
+ | `bw:cancel` | -- | Configurator cancelled |
96
+
97
+ ## Option 2: JavaScript mount functions
98
+
99
+ For programmatic control in an Astro, Vite, or bundled project, install the package and import the ES module:
100
+
101
+ ```bash
102
+ npm install @code-collective/booking-widget
103
+ ```
104
+
105
+ ```js
106
+ import { mountConfigurator, mountCheckout, mountCartOverview } from '@code-collective/booking-widget';
107
+ import '@code-collective/booking-widget/style.css';
108
+
109
+ const widget = await mountConfigurator(document.getElementById('configurator'), {
110
+ productId: 'your-product-id',
111
+ checkoutKey: 'your-checkout-key',
112
+ apiBaseUrl: 'https://checkout.yourdomain.com',
113
+ onCartChange({ itemCount, totalFormatted }) {
114
+ console.log(`${itemCount} items, ${totalFormatted}`);
115
+ },
116
+ });
117
+
118
+ // Later: widget.destroy();
119
+ ```
120
+
121
+ ### Mount functions
122
+
123
+ **`mountConfigurator(target, config)`** — Product selection wizard
124
+
125
+ | Config | Required | Description |
126
+ |---|---|---|
127
+ | `productId` | Yes | OCTO product ID |
128
+ | `checkoutKey` | No | Supplier checkout key |
129
+ | `apiBaseUrl` | No | Checkout API URL |
130
+ | `wizardPages` | No | Wizard step ordering |
131
+ | `autoSelectSingleTimeSlot` | No | Skip time picker if single slot |
132
+ | `onCartChange` | No | Callback: `({ itemCount, cartItemId, totalFormatted })` |
133
+ | `onCancel` | No | Callback when cancelled |
134
+
135
+ **`mountCheckout(target, config)`** — Cart review, contact form, payment
136
+
137
+ | Config | Required | Description |
138
+ |---|---|---|
139
+ | `checkoutKey` | No | Supplier checkout key |
140
+ | `apiBaseUrl` | No | Checkout API URL |
141
+ | `onClose` | No | Callback when closed |
142
+ | `onOrderConfirmed` | No | Callback: `({ cartToken, value, currency })` |
143
+
144
+ **`mountCartOverview(target, config)`** — Cart summary
145
+
146
+ | Config | Required | Description |
147
+ |---|---|---|
148
+ | `checkoutKey` | No | Supplier checkout key |
149
+ | `apiBaseUrl` | No | Checkout API URL |
150
+ | `display` | No | `bar` or `button` |
151
+ | `onCheckout` | No | Callback when checkout clicked |
152
+
153
+ All mount functions return `Promise<{ destroy(): void }>`.
154
+
155
+ ## Option 3: Svelte components
156
+
157
+ Install the package and import Svelte components directly for full reactivity:
158
+
159
+ ```bash
160
+ npm install @code-collective/booking-widget
161
+ ```
162
+
163
+ ```svelte
164
+ <script lang="ts">
165
+ import { TicketConfigurator, Checkout, CartBar, CartOverviewButton } from '@code-collective/booking-widget';
166
+ import { ApiClient, SessionManager, CartManager } from '@code-collective/booking-widget';
167
+ import '@code-collective/booking-widget/style.css';
168
+
169
+ const api = new ApiClient('https://checkout.yourdomain.com');
170
+ const sessionManager = new SessionManager(api);
171
+ const cartManager = new CartManager(api);
172
+ sessionManager.startBackgroundRefresh();
173
+
174
+ let ready = $state(false);
175
+ sessionManager.ensureSession('your-checkout-key').then(() => { ready = true; });
176
+ </script>
177
+
178
+ {#if ready}
179
+ <TicketConfigurator {api} {cartManager} productId="your-product-id" />
180
+ <CartOverviewButton {api} {cartManager} />
181
+ <Checkout {api} />
182
+ {/if}
183
+ ```
184
+
185
+ ## Astro integration
186
+
187
+ ### Script tag approach
188
+
189
+ ```astro
190
+ ---
191
+ const product = await getProduct(Astro.params.slug);
192
+ ---
193
+
194
+ <bw-configurator product-id={product.id} checkout-key={product.checkoutKey}></bw-configurator>
195
+ <bw-cart display="bar" checkout-key={product.checkoutKey}></bw-cart>
196
+ <bw-checkout checkout-key={product.checkoutKey}></bw-checkout>
197
+
198
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@latest/dist/booking-widget.min.css" />
199
+ <script is:inline src="https://cdn.jsdelivr.net/npm/@code-collective/booking-widget@latest/dist/booking-widget.min.js"></script>
200
+ ```
201
+
202
+ ### Svelte island approach
203
+
204
+ ```bash
205
+ npx astro add svelte
206
+ npm install @code-collective/booking-widget
207
+ ```
208
+
209
+ ```astro
210
+ ---
211
+ import BookingWidget from '../components/BookingWidget.svelte';
212
+ const product = await getProduct(Astro.params.slug);
213
+ ---
214
+
215
+ <BookingWidget
216
+ client:load
217
+ productId={product.id}
218
+ checkoutKey={product.checkoutKey}
219
+ apiBaseUrl="https://checkout.yourdomain.com"
220
+ />
221
+ ```
222
+
223
+ ## Wizard page ordering
224
+
225
+ Control the step sequence with `wizardPages`:
226
+
227
+ **Option-first (default):**
228
+ ```json
229
+ [["option", "age-category"], ["date", "time"], ["pickup"]]
230
+ ```
231
+
232
+ **Age-first:**
233
+ ```json
234
+ [["age-category"], ["date", "time"], ["option"], ["pickup"]]
235
+ ```
236
+
237
+ ## Theming
238
+
239
+ The widget reads CSS custom properties. It automatically picks up site variables (`--header-background`, `--default-font-family`, `--radius`) or can be themed directly:
240
+
241
+ ```css
242
+ :root {
243
+ --bw-color-primary: #0066CC;
244
+ --bw-color-primary-dark: #004C99;
245
+ --bw-font-family: 'Inter', sans-serif;
246
+ --bw-radius-md: 4px;
247
+ }
248
+ ```
249
+
250
+ | Variable | Fallback | Default |
251
+ |---|---|---|
252
+ | `--bw-color-primary` | `--header-background` | `#E30613` |
253
+ | `--bw-color-primary-dark` | `--footer-background` | `#C00510` |
254
+ | `--bw-color-primary-light` | -- | `rgba(227,6,19,0.08)` |
255
+ | `--bw-color-text` | -- | `#212121` |
256
+ | `--bw-color-text-secondary` | -- | `#757575` |
257
+ | `--bw-color-border` | -- | `#E0E0E0` |
258
+ | `--bw-color-bg` | -- | `#FFFFFF` |
259
+ | `--bw-color-surface` | -- | `#F5F5F5` |
260
+ | `--bw-color-success` | -- | `#4CAF50` |
261
+ | `--bw-color-error` | `--header-background` | `#E30613` |
262
+ | `--bw-font-family` | `--default-font-family` | `Roboto, system` |
263
+ | `--bw-radius-sm` | -- | `4px` |
264
+ | `--bw-radius-md` | `--radius` | `8px` |
265
+ | `--bw-radius-lg` | -- | `12px` |
266
+ | `--bw-transition` | -- | `0.15s ease` |
@@ -0,0 +1,2 @@
1
+ :root{--bw-color-primary:var(--header-background,#e30613);--bw-color-primary-dark:var(--footer-background,#c00510);--bw-color-primary-light:#e3061314;--bw-color-text:#212121;--bw-color-text-secondary:#757575;--bw-color-border:#e0e0e0;--bw-color-bg:#fff;--bw-color-surface:#f5f5f5;--bw-color-success:#4caf50;--bw-color-error:var(--header-background,#e30613);--bw-font-family:var(--default-font-family,"Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);--bw-radius-sm:4px;--bw-radius-md:var(--radius,8px);--bw-radius-lg:12px;--bw-radius-pill:9999px;--bw-transition:.15s ease;--bw-shadow-1:0 1px 3px #0000001a, 0 1px 2px #0000000f;--bw-shadow-2:0 4px 12px #00000014, 0 2px 4px #0000000a;--bw-shadow-3:0 10px 24px #0000001a, 0 4px 8px #0000000a}*{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--bw-font-family);color:var(--bw-color-text);background:var(--bw-color-bg);-webkit-font-smoothing:antialiased;font-size:14px;line-height:1.5}button{cursor:pointer;font-family:inherit}input,select,textarea{font-family:inherit}@keyframes spin{to{transform:rotate(360deg)}}.spinner{border:3px solid var(--bw-color-border);border-top-color:var(--bw-color-primary);border-radius:50%;width:36px;height:36px;animation:.7s linear infinite spin}.loading-center{flex:1;justify-content:center;align-items:center;min-height:120px;display:flex}.page-header{border-bottom:1px solid var(--bw-color-border);background:var(--bw-color-bg);align-items:center;gap:8px;padding:12px 16px;display:flex}.page-header h2{letter-spacing:-.01em;font-size:18px;font-weight:700}.page-header .spacer{flex:1}.icon-btn{border-radius:var(--bw-radius-pill);width:36px;height:36px;color:var(--bw-color-text);transition:background var(--bw-transition);background:0 0;border:none;justify-content:center;align-items:center;font-size:20px;display:flex}.icon-btn:hover{background:var(--bw-color-surface)}.card{background:var(--bw-color-bg);border:1px solid var(--bw-color-border);border-radius:var(--bw-radius-lg);transition:border-color var(--bw-transition);padding:16px}.card-selectable{cursor:pointer;text-align:left}.card-selectable:hover{border-color:var(--bw-color-text)}.card-selected{border-color:var(--bw-color-text);border-width:2px}.action-bar{border-top:1px solid var(--bw-color-border);background:var(--bw-color-bg);z-index:10;flex-shrink:0;gap:10px;padding:12px 16px;display:flex;position:sticky;bottom:0}.action-bar .btn-secondary{border:1px solid var(--bw-color-border);background:var(--bw-color-bg);height:48px;padding:0 20px}.action-bar .btn-primary{flex:1;height:48px;font-size:16px;font-weight:700;position:relative}.action-bar .btn-primary .arrow{font-size:20px;position:absolute;right:16px}.btn{border-radius:var(--bw-radius-md);transition:background var(--bw-transition), box-shadow var(--bw-transition), opacity var(--bw-transition);border:none;justify-content:center;align-items:center;gap:8px;padding:10px 20px;font-size:14px;font-weight:600;display:inline-flex}.btn:disabled{opacity:.45;cursor:default;pointer-events:none}.btn-primary{background:var(--bw-color-primary);color:#fff}.btn-primary:hover:not(:disabled){background:var(--bw-color-primary-dark);box-shadow:var(--bw-shadow-1)}.btn-secondary{background:var(--bw-color-bg);color:var(--bw-color-text)}.btn-secondary:hover:not(:disabled){background:var(--bw-color-border)}.btn-outline{border:1px solid var(--bw-color-primary);color:var(--bw-color-primary);background:0 0}.btn-outline:hover:not(:disabled){background:var(--bw-color-primary-light)}.btn-split{justify-content:space-between;padding:0 20px}.input{border:1px solid var(--bw-color-border);border-radius:var(--bw-radius-md);width:100%;transition:border-color var(--bw-transition), box-shadow var(--bw-transition);outline:none;padding:10px 12px;font-size:14px}.input:focus{border-color:var(--bw-color-primary);box-shadow:0 0 0 3px var(--bw-color-primary-light)}.input-error{border-color:var(--bw-color-error);background:#fef2f2}.input-error:focus{box-shadow:0 0 0 3px #e306131f}.section-title{color:var(--bw-color-text-secondary);margin-bottom:12px;font-size:14px;font-weight:400}.layout.svelte-idp8p9{align-items:center;gap:12px;display:flex}.text.svelte-idp8p9{flex:1}.heading.svelte-idp8p9{margin-bottom:4px;font-size:15px;font-weight:700}.body.svelte-idp8p9{color:var(--bw-color-text-secondary);font-size:13px;line-height:1.5}.radio.svelte-idp8p9{border:2px solid var(--bw-color-border);border-radius:50%;flex-shrink:0;width:22px;height:22px}.radio-selected.svelte-idp8p9{border-color:var(--bw-color-text);background:var(--bw-color-text)}.pricing.svelte-19wqhng{margin-top:8px;font-size:13px;font-weight:700}.row.svelte-bzhcxd{align-items:center;display:flex}.info.svelte-bzhcxd{flex-direction:column;flex:1;gap:2px;display:flex}.name.svelte-bzhcxd{font-size:15px;font-weight:700}.price.svelte-bzhcxd{color:var(--bw-color-text-secondary);font-size:13px}.stepper.svelte-bzhcxd{align-items:center;gap:4px;display:flex}.step-btn.svelte-bzhcxd{border:1.5px solid var(--bw-color-border);width:40px;height:40px;color:var(--bw-color-primary);transition:background var(--bw-transition), color var(--bw-transition), border-color var(--bw-transition);background:0 0;border-radius:50%;justify-content:center;align-items:center;font-size:20px;display:flex}.step-btn.svelte-bzhcxd:hover:not(:disabled){background:var(--bw-color-primary);color:#fff}.step-btn.svelte-bzhcxd:disabled{opacity:.3;cursor:default}.qty.svelte-bzhcxd{text-align:center;font-variant-numeric:tabular-nums;min-width:32px;font-size:17px;font-weight:700}.calendar.svelte-10gu2tq{width:100%}.header.svelte-10gu2tq{justify-content:space-between;align-items:center;margin-bottom:16px;display:flex}.month.svelte-10gu2tq{font-size:16px;font-weight:700}.nav-btn.svelte-10gu2tq{border:1.5px solid var(--bw-color-border);width:36px;height:36px;color:var(--bw-color-text);transition:border-color var(--bw-transition);background:0 0;border-radius:50%;justify-content:center;align-items:center;font-size:20px;display:flex}.nav-btn.svelte-10gu2tq:hover{border-color:var(--bw-color-text)}.day-names.svelte-10gu2tq{text-align:center;grid-template-columns:repeat(7,1fr);margin-bottom:8px;display:grid}.day-names.svelte-10gu2tq span:where(.svelte-10gu2tq){color:var(--bw-color-text-secondary);padding:4px 0;font-size:11px;font-weight:700}.grid.svelte-10gu2tq{grid-template-columns:repeat(7,1fr);gap:6px;display:grid}.cell.svelte-10gu2tq{border-radius:var(--bw-radius-md);min-height:48px;transition:border-color var(--bw-transition), background var(--bw-transition);background:0 0;border:1.5px solid #0000;flex-direction:column;justify-content:center;align-items:center;padding:4px 2px;font-size:14px;display:flex}.cell.empty.svelte-10gu2tq{pointer-events:none}.cell.available.svelte-10gu2tq{color:var(--bw-color-text);border-color:var(--bw-color-border);font-weight:600}.cell.available.svelte-10gu2tq:hover{border-color:var(--bw-color-text)}.cell.selected.svelte-10gu2tq{border-color:var(--bw-color-text);border-width:2px;font-weight:700}.cell.sold-out.svelte-10gu2tq{color:var(--bw-color-text-secondary);cursor:default;text-decoration:line-through}.cell.unavailable.svelte-10gu2tq{color:#d1d5db;cursor:default}.day-num.svelte-10gu2tq{line-height:1}.day-price.svelte-10gu2tq{color:var(--bw-color-text-secondary);margin-top:2px;font-size:9px;font-weight:600;line-height:1}.selected.svelte-10gu2tq .day-price:where(.svelte-10gu2tq){color:var(--bw-color-text)}.hint.svelte-1hu99a4{text-align:center;color:var(--bw-color-text-secondary);padding:12px;font-size:14px}.slots.svelte-1hu99a4{flex-direction:column;gap:10px;display:flex}.wizard.svelte-9w5z1v{flex-direction:column;height:100%;max-height:100%;display:flex;overflow:hidden}.wizard-header.svelte-9w5z1v{border-bottom:1px solid var(--bw-color-border);padding:20px 16px 16px}.wizard-header.svelte-9w5z1v h2:where(.svelte-9w5z1v){font-size:20px;font-weight:800}.wizard-body.svelte-9w5z1v{flex:1;padding:16px;overflow-y:auto}.section.svelte-9w5z1v{margin-bottom:24px}.option-list.svelte-9w5z1v,.pickup-list.svelte-9w5z1v,.unit-list.svelte-9w5z1v{flex-direction:column;gap:10px;display:flex}.dialog-backdrop.svelte-9w5z1v{z-index:100;background:#00000059;justify-content:center;align-items:center;width:100%;height:100%;display:flex;position:fixed;top:0;left:0}.dialog.svelte-9w5z1v{border-radius:var(--bw-radius-lg);width:90%;max-width:360px;box-shadow:var(--bw-shadow-3);background:#fff;padding:24px}.dialog-title.svelte-9w5z1v{margin-bottom:8px;font-size:17px;font-weight:700}.dialog-body.svelte-9w5z1v{color:var(--bw-color-text-secondary);margin-bottom:24px;font-size:14px}.dialog-actions.svelte-9w5z1v{justify-content:flex-end;gap:8px;display:flex}.dialog-btn-text.svelte-9w5z1v{color:var(--bw-color-primary);border-radius:var(--bw-radius-md);background:0 0;border:none;padding:10px 16px;font-size:14px;font-weight:600}.dialog-btn-text.svelte-9w5z1v:hover{background:var(--bw-color-primary-light)}.dialog-btn-fill.svelte-9w5z1v{background:var(--bw-color-primary);color:#fff;border-radius:var(--bw-radius-md);border:none;padding:10px 20px;font-size:14px;font-weight:600}.dialog-btn-fill.svelte-9w5z1v:hover{background:var(--bw-color-primary-dark)}.form.svelte-12xyhj1{flex-direction:column;gap:14px;display:flex}.field.svelte-12xyhj1{flex-direction:column;gap:4px;display:flex}label.svelte-12xyhj1{color:var(--bw-color-text-secondary);font-size:13px;font-weight:600}.consent.svelte-19pmjwi{flex-direction:column;gap:12px;display:flex}.check.svelte-19pmjwi{cursor:pointer;align-items:flex-start;gap:10px;font-size:13px;line-height:1.4;display:flex}.check.error.svelte-19pmjwi span:where(.svelte-19pmjwi){color:var(--bw-color-error)}input[type=checkbox].svelte-19pmjwi{accent-color:var(--bw-color-primary);flex-shrink:0;width:16px;height:16px;margin-top:2px}.timer.svelte-1u82ue3{color:var(--bw-color-text-secondary);font-variant-numeric:tabular-nums;font-size:13px;font-weight:600}.payment-page.svelte-1ubcp68{flex-direction:column;height:100%;display:flex}.body.svelte-1ubcp68{flex:1;padding:16px;overflow-y:auto}.amount-bar.svelte-1ubcp68{background:var(--bw-color-surface);border-radius:var(--bw-radius-lg);justify-content:space-between;align-items:center;margin-bottom:20px;padding:16px;font-size:15px;font-weight:600;display:flex}.amount.svelte-1ubcp68{color:var(--bw-color-primary);font-size:18px;font-weight:700}.brands.svelte-1ubcp68{gap:8px;margin-bottom:16px;display:flex}.brand.svelte-1ubcp68{border:1px solid var(--bw-color-border);border-radius:var(--bw-radius-sm);color:var(--bw-color-text-secondary);letter-spacing:.02em;padding:4px 10px;font-size:11px;font-weight:700}.error-state.svelte-1ubcp68{text-align:center;padding:32px 16px}.error-icon.svelte-1ubcp68{border:2px solid var(--bw-color-border);width:48px;height:48px;color:var(--bw-color-text-secondary);border-radius:50%;justify-content:center;align-items:center;margin:0 auto 16px;font-size:24px;display:flex}.error-title.svelte-1ubcp68{margin-bottom:8px;font-size:16px;font-weight:600}.error-msg.svelte-1ubcp68{color:var(--bw-color-text-secondary);font-size:14px}.result.svelte-16gfovn{text-align:center;flex-direction:column;justify-content:center;align-items:center;height:100%;padding:40px 24px;display:flex}.hint.svelte-16gfovn{color:var(--bw-color-text-secondary);margin-top:16px;font-size:14px}.icon.svelte-16gfovn{border-radius:50%;justify-content:center;align-items:center;width:64px;height:64px;margin-bottom:20px;font-size:32px;display:flex}.icon.success.svelte-16gfovn{border:2px solid var(--bw-color-success);color:var(--bw-color-success);background:#4caf5014}.icon.failure.svelte-16gfovn{border:2px solid var(--bw-color-error);color:var(--bw-color-error);background:var(--bw-color-primary-light)}h2.svelte-16gfovn{margin-bottom:8px;font-size:20px;font-weight:700}.desc.svelte-16gfovn{color:var(--bw-color-text-secondary);max-width:280px;margin-bottom:28px;font-size:14px;line-height:1.5}.edit-view.svelte-15l4305{flex-direction:column;height:100%;max-height:100%;display:flex;overflow:hidden}.modal.svelte-i0rtg0{background:var(--bw-color-surface);flex-direction:column;height:100%;max-height:100%;display:flex;overflow:hidden}.body.svelte-i0rtg0{flex:1;padding:16px;overflow-y:auto}.cart-header.svelte-i0rtg0{justify-content:space-between;align-items:center;margin-bottom:20px;display:flex}.cart-title.svelte-i0rtg0{font-size:22px;font-weight:800}.cart-header-right.svelte-i0rtg0{align-items:center;gap:12px;display:flex}.keep-shopping-btn.svelte-i0rtg0{border-radius:var(--bw-radius-md);color:#222;cursor:pointer;background:0 0;border:2px solid #222;padding:8px 16px;font-size:13px;font-weight:600}.keep-shopping-btn.svelte-i0rtg0:hover{background:#f5f5f5}.cart-card.svelte-i0rtg0{border:1px solid var(--bw-color-border);border-radius:var(--bw-radius-lg);margin-bottom:16px;padding:20px}.cart-card-top.svelte-i0rtg0{justify-content:space-between;align-items:flex-start;gap:16px;display:flex}.cart-product.svelte-i0rtg0{flex:1;font-size:16px;font-weight:700}.cart-item-total.svelte-i0rtg0{white-space:nowrap;font-size:16px;font-weight:800}.cart-detail-lines.svelte-i0rtg0{margin-top:4px}.cart-detail.svelte-i0rtg0{color:var(--bw-color-text-secondary);font-size:13px;line-height:1.5}.cart-divider.svelte-i0rtg0{border-top:1px dashed var(--bw-color-border);margin:14px 0}.cart-units.svelte-i0rtg0{flex-direction:column;gap:6px;margin-bottom:14px;display:flex}.cart-unit-line.svelte-i0rtg0{justify-content:space-between;align-items:center;font-size:14px;display:flex}.cart-unit-label.svelte-i0rtg0{color:#333}.cart-unit-price.svelte-i0rtg0{font-variant-numeric:tabular-nums;font-weight:600}.cart-actions.svelte-i0rtg0{gap:16px;display:flex}.action-edit.svelte-i0rtg0{color:var(--bw-color-primary);cursor:pointer;background:0 0;border:none;padding:0;font-size:13px;font-weight:700}.action-edit.svelte-i0rtg0:hover{text-decoration:underline}.action-remove.svelte-i0rtg0{color:#555;cursor:pointer;background:0 0;border:none;padding:0;font-size:13px;font-weight:600}.action-remove.svelte-i0rtg0:hover{text-decoration:underline}.cart-total-divider.svelte-i0rtg0{border-top:3px solid #111;margin:8px 0 20px}.cart-total-row.svelte-i0rtg0{justify-content:space-between;align-items:center;margin-bottom:20px;font-size:16px;font-weight:700;display:flex}.cart-total-amount.svelte-i0rtg0{font-size:20px;font-weight:800}.checkout-btn.svelte-i0rtg0{background:var(--bw-color-primary);color:#fff;border-radius:var(--bw-radius-md);cursor:pointer;text-align:center;border:none;width:100%;padding:16px;font-size:16px;font-weight:700;display:block}.checkout-btn.svelte-i0rtg0:hover{background:var(--bw-color-primary-dark)}.contact-header.svelte-i0rtg0{justify-content:space-between;align-items:center;margin-bottom:20px;display:flex}.contact-title.svelte-i0rtg0{font-size:16px;font-weight:700}.required-hint.svelte-i0rtg0{color:var(--bw-color-primary);font-size:12px}.pay-bar.svelte-i0rtg0{background:var(--bw-color-primary);color:#fff;flex-shrink:0;align-items:center;display:flex;position:sticky;bottom:0}.pay-bar-total.svelte-i0rtg0{padding:0 20px;font-size:16px;font-weight:700}.pay-bar-btn.svelte-i0rtg0{color:#fff;background:0 0;border:none;flex:1;justify-content:flex-end;align-items:center;gap:8px;height:52px;padding:0 20px;font-size:16px;font-weight:700;display:flex}.pay-bar-btn.svelte-i0rtg0 .arrow:where(.svelte-i0rtg0){font-size:20px}.cart-bar.svelte-1xt0fxx{border-top:1px solid var(--bw-color-border);background:#fff;justify-content:space-between;align-items:center;width:100%;padding:12px 16px;display:flex;box-shadow:0 -2px 8px #0000000f}.cart-info.svelte-1xt0fxx{flex-direction:column;gap:2px;display:flex}.item-count.svelte-1xt0fxx{color:var(--bw-color-text-secondary);font-size:12px}.total.svelte-1xt0fxx{font-size:16px;font-weight:700}.cart-overview-btn.svelte-16bjfem{background:var(--bw-color-primary);color:#fff;cursor:pointer;border:none;border-radius:999px;align-items:center;gap:10px;width:100%;padding:12px 20px;font-size:14px;font-weight:700;transition:background .15s;display:flex}.cart-overview-btn.svelte-16bjfem:hover{background:var(--bw-color-primary-dark)}.cart-icon.svelte-16bjfem{flex-shrink:0;width:18px;height:18px}.cart-badge.svelte-16bjfem{min-width:22px;height:22px;color:var(--bw-color-primary);background:#fff;border-radius:5px;flex-shrink:0;justify-content:center;align-items:center;padding:0 5px;font-size:12px;font-weight:800;display:flex}.cart-total.svelte-16bjfem{text-align:left;flex:1;font-size:14px;font-weight:700}.cart-sep.svelte-16bjfem{background:#ffffff59;flex-shrink:0;width:1px;height:16px}.cart-timer.svelte-16bjfem{font-variant-numeric:tabular-nums;opacity:.85;flex-shrink:0;font-size:13px}
2
+ /*$vite$:1*/