@funnelsgrove/payments 0.15.7 → 0.15.8

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/README.md CHANGED
@@ -154,3 +154,22 @@ npm publish --workspace @funnelsgrove/payments --access public
154
154
  ```
155
155
 
156
156
  The build normalizes generated relative ESM imports to explicit `.js` files for published package consumers.
157
+
158
+ ## Checkout email repair
159
+
160
+ [Checkout email recovery](../../docs/product-specs/billing.md#checkout-email-recovery)
161
+ owns the behavior. Pass `onCustomerEmailCommit` to wallet surfaces and the card
162
+ checkout dialog. It must save the access email, adopt the returned Funnel User, and
163
+ update the `customerEmail` and `userId` inputs used by checkout. A wallet surface
164
+ renders a Continue control and `CheckoutEmailDialog` when repair is required.
165
+ `onResolveCustomerEmail` can resolve a known identity before asking for input;
166
+ its caller must also adopt the resolved identity. `emailDialogContent` customizes
167
+ prompt copy. Keep `beforeConfirm` for immediate preparation only, without awaiting
168
+ human input or changing the access identity.
169
+
170
+ `CheckoutEmailDialog` is also exported for funnel-owned checkout entry controls,
171
+ including legacy wallet launchers. Mount it before wallet launch, persist through
172
+ `onSave`, and close through `onClose`; its completion never launches a wallet.
173
+ `isValidCheckoutEmail` and `isCheckoutEmailError` share validation and recovery
174
+ classification. `onCustomerEmailChange` in the card dialog reports a committed
175
+ email, not each draft keystroke, so typing cannot prepare sessions for unsaved input.
@@ -0,0 +1,15 @@
1
+ export type CheckoutEmailDialogProps = {
2
+ customerEmail?: string | null;
3
+ rejectedEmail?: string | null;
4
+ onSave: (email: string) => Promise<string | null | void>;
5
+ onClose: () => void;
6
+ title?: string;
7
+ description?: string;
8
+ emailLabel?: string;
9
+ placeholder?: string;
10
+ invalidMessage?: string;
11
+ continueLabel?: string;
12
+ cancelLabel?: string;
13
+ };
14
+ /** Mount before wallet launch; saving never resumes an already open wallet confirmation. */
15
+ export declare function CheckoutEmailDialog({ customerEmail, rejectedEmail, onSave, onClose, title, description, emailLabel, placeholder, invalidMessage, continueLabel, cancelLabel, }: CheckoutEmailDialogProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useRef, useState } from 'react';
4
+ import { isValidCheckoutEmail, normalizeCheckoutEmailResult } from '../services/checkoutEmail.js';
5
+ /** Mount before wallet launch; saving never resumes an already open wallet confirmation. */
6
+ export function CheckoutEmailDialog({ customerEmail, rejectedEmail, onSave, onClose, title = 'Your email for access', description = 'Enter the email you want to use to access your purchase.', emailLabel = 'Email', placeholder = 'Enter your email', invalidMessage = 'Enter a valid email address.', continueLabel = 'Continue', cancelLabel = 'Cancel', }) {
7
+ var _a;
8
+ const dialogRef = useRef(null);
9
+ const busyRef = useRef(false);
10
+ const [draft, setDraft] = useState((_a = customerEmail === null || customerEmail === void 0 ? void 0 : customerEmail.trim()) !== null && _a !== void 0 ? _a : '');
11
+ const [busy, setBusy] = useState(false);
12
+ const [error, setError] = useState(null);
13
+ const titleId = useId();
14
+ const errorId = useId();
15
+ useEffect(() => {
16
+ const dialog = dialogRef.current;
17
+ dialog === null || dialog === void 0 ? void 0 : dialog.showModal();
18
+ return () => dialog === null || dialog === void 0 ? void 0 : dialog.close();
19
+ }, []);
20
+ const submit = async (event) => {
21
+ event.preventDefault();
22
+ if (busyRef.current)
23
+ return;
24
+ const email = draft.trim();
25
+ if (!isValidCheckoutEmail(email) || email.toLowerCase() === (rejectedEmail === null || rejectedEmail === void 0 ? void 0 : rejectedEmail.trim().toLowerCase())) {
26
+ setError(invalidMessage);
27
+ return;
28
+ }
29
+ busyRef.current = true;
30
+ setBusy(true);
31
+ setError(null);
32
+ try {
33
+ const saved = await onSave(email);
34
+ normalizeCheckoutEmailResult(saved, email, invalidMessage);
35
+ onClose();
36
+ }
37
+ catch (saveError) {
38
+ setError(saveError instanceof Error ? saveError.message : 'Unable to save your email. Please try again.');
39
+ }
40
+ finally {
41
+ busyRef.current = false;
42
+ setBusy(false);
43
+ }
44
+ };
45
+ return (_jsxs("dialog", { ref: dialogRef, className: 'checkout-email-dialog bg-card text-foreground border-border', "aria-labelledby": titleId, onCancel: (event) => {
46
+ event.preventDefault();
47
+ if (!busyRef.current)
48
+ onClose();
49
+ }, children: [_jsxs("form", { onSubmit: submit, noValidate: true, "aria-busy": busy, children: [_jsx("h2", { id: titleId, children: title }), _jsx("p", { children: description }), _jsxs("label", { children: [emailLabel, _jsx("input", { type: 'email', autoComplete: 'email', inputMode: 'email', autoFocus: true, className: 'bg-background text-foreground border-border', value: draft, placeholder: placeholder, disabled: busy, "aria-invalid": Boolean(error), "aria-describedby": error ? errorId : undefined, onChange: (event) => { setDraft(event.target.value); setError(null); } })] }), error ? _jsx("p", { id: errorId, role: 'alert', children: error }) : null, _jsxs("div", { className: 'checkout-email-dialog-actions', children: [_jsx("button", { type: 'button', className: 'bg-background text-foreground border-border', disabled: busy, onClick: onClose, children: cancelLabel }), _jsx("button", { type: 'submit', className: 'bg-accent text-foreground border-border', disabled: busy, children: busy ? 'Saving…' : continueLabel })] })] }), _jsx("style", { children: `
50
+ .checkout-email-dialog { color-scheme: light dark; box-sizing: border-box; width: min(420px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); overflow-y: auto; margin: auto; padding: 24px; border: 1px solid GrayText; border-radius: 20px; background: Canvas; color: CanvasText; font: inherit; }
51
+ .dark .checkout-email-dialog, [data-theme=dark] .checkout-email-dialog { color-scheme: dark; }
52
+ .light .checkout-email-dialog, [data-theme=light] .checkout-email-dialog { color-scheme: light; }
53
+ .checkout-email-dialog::backdrop { background: rgb(0 0 0 / 45%); }
54
+ .checkout-email-dialog h2 { color: inherit; margin: 0 0 12px; font-size: 24px; line-height: 1.2; }
55
+ .checkout-email-dialog p { margin: 0 0 20px; line-height: 1.5; }
56
+ .checkout-email-dialog label { display: grid; gap: 8px; }
57
+ .checkout-email-dialog input { box-sizing: border-box; width: 100%; min-height: 48px; padding: 12px; border: 1px solid GrayText; border-radius: 10px; background: Canvas; color: CanvasText; font: inherit; font-size: 16px; }
58
+ .checkout-email-dialog input::placeholder { color: GrayText; }
59
+ .checkout-email-dialog [role=alert] { margin-top: 12px; font-weight: 600; }
60
+ .checkout-email-dialog-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
61
+ .checkout-email-dialog button { flex: 1; padding: 12px; min-height: 48px; border: 1px solid GrayText; border-radius: 10px; background: Canvas; color: CanvasText; font: inherit; cursor: pointer; }
62
+ .checkout-email-dialog button[type=submit] { font-weight: 700; border: 2px solid CanvasText; }
63
+ .checkout-email-dialog button:disabled { opacity: .6; cursor: wait; }
64
+ .checkout-email-dialog :focus-visible { outline: 2px solid Highlight; outline-offset: 3px; }
65
+ ` })] }));
66
+ }
package/dist/index.d.ts CHANGED
@@ -12,3 +12,5 @@ export * from './providers/paymentProvider.types.js';
12
12
  export * from './providers/stripe/index.js';
13
13
  export * from './providers/solidgate/index.js';
14
14
  export { ManageSubscriptionScreen, type ManageSubscriptionContent, type ManageSubscriptionScreenProps, } from './components/ManageSubscriptionScreen.js';
15
+ export { isCheckoutEmailError, isValidCheckoutEmail } from './services/checkoutEmail.js';
16
+ export * from './components/CheckoutEmailDialog.js';
package/dist/index.js CHANGED
@@ -15,3 +15,5 @@ export * from './providers/stripe/index.js';
15
15
  export * from './providers/solidgate/index.js';
16
16
  // Provider-neutral subscription management UI.
17
17
  export { ManageSubscriptionScreen, } from './components/ManageSubscriptionScreen.js';
18
+ export { isCheckoutEmailError, isValidCheckoutEmail } from './services/checkoutEmail.js';
19
+ export * from './components/CheckoutEmailDialog.js';
@@ -0,0 +1 @@
1
+ export declare const sharedStripeCheckoutV2Styles = "\n.shared-checkout-v2-overlay {\n position: fixed;\n inset: 0;\n z-index: 110;\n display: flex;\n align-items: stretch;\n justify-content: center;\n overflow: hidden;\n background: #fff;\n}\n\n.shared-checkout-v2-dialog {\n width: min(100%, 430px);\n height: 100svh;\n max-height: 100svh;\n overflow: hidden;\n background: #fff;\n}\n\n@media (min-width: 640px) {\n .shared-checkout-v2-overlay:has(.shared-checkout-v2-dialog[data-variant='compact']) {\n align-items: center;\n padding: 24px;\n background: rgb(0 0 0 / 48%);\n }\n\n .shared-checkout-v2-dialog[data-variant='compact'] {\n width: min(100%, 520px);\n height: auto;\n max-height: calc(100svh - 48px);\n border-radius: 24px;\n box-shadow: 0 24px 70px rgb(0 0 0 / 28%);\n }\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] {\n height: auto;\n max-height: min(100svh, 760px);\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-header {\n min-height: 88px;\n padding: 0 72px;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-header h2 {\n font-size: 27px;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-close {\n right: 22px;\n left: auto;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-summary {\n padding: 0 36px;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-total {\n min-height: 82px;\n border: 1px solid #ececef;\n border-radius: 16px;\n padding: 0 22px;\n background: #fbfbfc;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-total svg {\n display: none;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-payment {\n padding-right: 36px;\n padding-left: 36px;\n}\n\n.shared-checkout-v2-shell[data-variant='compact'] .shared-checkout-v2-card-submit {\n border-radius: 14px;\n background: var(--shared-checkout-v2-button-color);\n text-transform: none;\n}\n\n.shared-checkout-v2-shell {\n height: 100%;\n max-height: 100svh;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n background: #fff;\n color: #303136;\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n.shared-checkout-v2-header {\n position: relative;\n min-height: 70px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 56px;\n background: #fff;\n}\n\n.shared-checkout-v2-header h2 {\n margin: 0;\n color: #020203;\n font-size: 24px;\n font-weight: 900;\n line-height: 1.15;\n letter-spacing: 0;\n text-align: center;\n}\n\n.shared-checkout-v2-close {\n position: absolute;\n left: 16px;\n top: 50%;\n width: 40px;\n height: 40px;\n border: 0;\n border-radius: 999px;\n background: #f2f2f3;\n color: #aaa;\n transform: translateY(-50%);\n cursor: pointer;\n}\n\n.shared-checkout-v2-close span,\n.shared-checkout-v2-close span::after {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 28px;\n height: 4px;\n border-radius: 999px;\n background: currentColor;\n content: '';\n}\n\n.shared-checkout-v2-close span {\n transform: translate(-50%, -50%) rotate(45deg);\n}\n\n.shared-checkout-v2-close span::after {\n transform: translate(-50%, -50%) rotate(90deg);\n}\n\n.shared-checkout-v2-summary {\n padding: 0 17px 0;\n background: #fff;\n}\n\n.shared-checkout-v2-countdown {\n margin: 0;\n min-height: 37px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 12px;\n background: color-mix(in srgb, var(--shared-checkout-v2-theme-color) 10%, #fff);\n color: var(--shared-checkout-v2-theme-color);\n font-size: 16px;\n font-weight: 900;\n line-height: 1.2;\n letter-spacing: 0;\n text-align: center;\n}\n\n.shared-checkout-v2-satisfaction {\n margin: 17px 0 21px;\n color: #2f3034;\n font-size: 19px;\n font-weight: 800;\n line-height: 1.15;\n letter-spacing: 0;\n text-align: center;\n}\n\n.shared-checkout-v2-satisfaction strong {\n color: var(--shared-checkout-v2-theme-color);\n}\n\n.shared-checkout-v2-price-stack {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.shared-checkout-v2-price-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n font-size: 18px;\n line-height: 1.2;\n letter-spacing: 0;\n}\n\n.shared-checkout-v2-price-row.is-muted {\n color: #9d9d9f;\n font-size: 17px;\n font-weight: 500;\n}\n\n.shared-checkout-v2-strike {\n text-decoration-line: line-through;\n text-decoration-thickness: 2px;\n}\n\n.shared-checkout-v2-price-row.is-discount {\n color: #040508;\n font-size: 17px;\n font-weight: 900;\n}\n\n.shared-checkout-v2-price-row.is-discount strong:last-child {\n color: #ff2544;\n}\n\n.shared-checkout-v2-promo {\n min-height: 42px;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n border-radius: 13px;\n background: #f0f0f0;\n padding: 0 14px;\n color: #8d8d90;\n font-size: 16px;\n font-weight: 500;\n line-height: 1.1;\n}\n\n.shared-checkout-v2-promo strong {\n color: #050609;\n font-weight: 900;\n}\n\n.shared-checkout-v2-total {\n margin-top: 20px;\n min-height: 76px;\n border-top: 1px solid #dedede;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n color: #303136;\n}\n\n.shared-checkout-v2-total span {\n font-size: 23px;\n font-weight: 800;\n line-height: 1;\n}\n\n.shared-checkout-v2-total strong {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: #303136;\n font-size: 25px;\n font-weight: 900;\n line-height: 1;\n}\n\n.shared-checkout-v2-total svg {\n width: 25px;\n height: 25px;\n fill: none;\n stroke: currentColor;\n stroke-width: 2;\n stroke-linejoin: round;\n}\n\n.shared-checkout-v2-total.is-plain {\n margin-top: 0;\n}\n\n.shared-checkout-v2-saved {\n width: fit-content;\n min-height: 36px;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n margin: -8px 0 9px auto;\n border-radius: 12px;\n background: #ffdce3;\n padding: 0 14px;\n color: #ff2544;\n font-size: 14px;\n font-weight: 900;\n line-height: 1.1;\n letter-spacing: 0;\n}\n\n.shared-checkout-v2-payment {\n min-height: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n background: #f2f2f3;\n padding: 9px 17px 32px;\n}\n\n.shared-checkout-v2-methods {\n display: grid;\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n gap: 42px;\n}\n\n.shared-checkout-v2-method {\n min-width: 0;\n min-height: 74px;\n box-sizing: border-box;\n border: 2px solid #e6e7eb;\n border-radius: 13px;\n background: #fff;\n color: #344376;\n padding: 9px 8px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 6px;\n cursor: pointer;\n}\n\n.shared-checkout-v2-method.is-selected {\n border: 3px solid #050505;\n}\n\n.shared-checkout-v2-tab-wallet {\n width: 58px;\n height: 36px;\n}\n\n.shared-checkout-v2-tab-wallet svg {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.shared-checkout-v2-tab-wallets {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n}\n\n.shared-checkout-v2-method strong {\n color: #344376;\n font-size: 20px;\n font-weight: 900;\n line-height: 1;\n letter-spacing: 0;\n}\n\n.shared-checkout-v2-tab-brands {\n display: flex;\n align-items: center;\n justify-content: center;\n max-width: 100%;\n gap: 4px;\n}\n\n.shared-checkout-v2-tab-brand {\n min-width: 0;\n width: 24px;\n height: 15px;\n}\n\n.shared-checkout-v2-tab-brand svg {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.shared-checkout-v2-wallet-panel,\n.shared-checkout-v2-card-panel {\n display: flex;\n flex-direction: column;\n height: 0;\n overflow: hidden;\n opacity: 0;\n pointer-events: none;\n}\n\n.shared-checkout-v2-wallet-panel[hidden],\n.shared-checkout-v2-card-panel[hidden] {\n display: none;\n}\n\n.shared-checkout-v2-wallet-panel {\n align-items: center;\n gap: 22px;\n padding-top: 5px;\n}\n\n.shared-checkout-v2-secure-pill {\n width: fit-content;\n min-height: 47px;\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin: 0 auto;\n border-radius: 12px;\n background: #dcffd0;\n padding: 0 22px;\n color: #207733;\n font-size: 18px;\n font-weight: 600;\n line-height: 1.1;\n letter-spacing: 0;\n}\n\n.shared-checkout-v2-secure-pill-icon {\n width: 24px;\n height: 24px;\n flex: none;\n color: #147232;\n}\n\n.shared-checkout-v2-wallet-shell {\n width: 100%;\n min-height: 124px;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.shared-checkout-v2-express-buttons {\n width: 100%;\n}\n\n.shared-checkout-v2-card-panel {\n position: relative;\n gap: 10px;\n margin-inline: -17px;\n background: #f2f2f3;\n padding: 16px 32px 92px;\n}\n\n.shared-checkout-v2-wallet-panel.is-visible,\n.shared-checkout-v2-card-panel.is-visible {\n height: auto;\n overflow: visible;\n opacity: 1;\n pointer-events: auto;\n}\n\n.shared-checkout-v2-wallet-panel:not(.is-visible),\n.shared-checkout-v2-card-panel:not(.is-visible) {\n padding-top: 0;\n padding-bottom: 0;\n}\n\n.shared-checkout-v2-email-field {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 7px;\n border: 0;\n border-radius: 0;\n background: transparent;\n margin-bottom: 14px;\n padding: 0;\n color: #303136;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n}\n\n.shared-checkout-v2-email-field.is-disabled {\n cursor: default;\n}\n\n.shared-checkout-v2-email-label {\n padding: 0 14px;\n color: #303136;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n}\n\n.shared-checkout-v2-email-control {\n min-height: 50px;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n border: 1px solid #dedede;\n background: #fff;\n box-shadow: 0 1px 2px rgb(16 24 40 / 8%);\n padding: 0 14px;\n}\n\n.shared-checkout-v2-email-input {\n width: 100%;\n min-height: 48px;\n box-sizing: border-box;\n border: 0;\n background: transparent;\n padding: 0;\n color: #303136;\n font: inherit;\n font-size: 18px;\n font-weight: 400;\n line-height: 1.2;\n outline: none;\n}\n\n.shared-checkout-v2-email-input:disabled {\n color: #74767c;\n opacity: 1;\n -webkit-text-fill-color: #74767c;\n}\n\n.shared-checkout-v2-email-input::placeholder {\n color: #8c909a;\n}\n\n.shared-checkout-v2-card-box {\n overflow: visible;\n border: 0;\n border-radius: 6px;\n background: transparent;\n box-shadow: none;\n}\n\n.shared-checkout-v2-country-field {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 7px;\n margin: 14px 0 0;\n color: #303136;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n}\n\n.shared-checkout-v2-country-label {\n padding: 0 14px;\n}\n\n.shared-checkout-v2-country-control {\n position: relative;\n display: block;\n}\n\n.shared-checkout-v2-country-control::after {\n position: absolute;\n right: 17px;\n top: 50%;\n width: 8px;\n height: 8px;\n border-right: 2px solid #6f7380;\n border-bottom: 2px solid #6f7380;\n content: '';\n pointer-events: none;\n transform: translateY(-65%) rotate(45deg);\n}\n\n.shared-checkout-v2-country-select {\n width: 100%;\n min-height: 50px;\n box-sizing: border-box;\n appearance: none;\n border: 1px solid #dedede;\n border-radius: 0;\n background: #fff;\n box-shadow: 0 1px 2px rgb(16 24 40 / 8%);\n color: #303136;\n font: inherit;\n font-size: 18px;\n font-weight: 400;\n line-height: 1.2;\n outline: none;\n padding: 0 44px 0 14px;\n}\n\n.shared-checkout-v2-error {\n margin: 0;\n color: #c43737;\n font-size: 13px;\n font-weight: 600;\n line-height: 1.35;\n}\n\n.shared-checkout-v2-card-submit {\n min-height: 60px;\n border: 0;\n border-radius: 11px;\n background: var(--shared-checkout-v2-button-color);\n color: #fff;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 14px;\n font-size: 22px;\n font-weight: 900;\n line-height: 1;\n letter-spacing: 0;\n cursor: pointer;\n}\n\n.shared-checkout-v2-card-submit:disabled {\n cursor: wait;\n opacity: 0.72;\n}\n\n.shared-checkout-v2-card-submit-icon {\n width: 26px;\n height: 26px;\n}\n\n.shared-checkout-v2-card-brands {\n min-height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n opacity: 0.95;\n}\n\n.shared-checkout-v2-card-brand {\n width: 42px;\n height: 25px;\n}\n\n.shared-checkout-v2-secure-pill--card {\n position: absolute;\n left: 50%;\n bottom: 16px;\n transform: translateX(-50%);\n white-space: nowrap;\n}\n\n.shared-checkout-v2-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.shared-checkout-special-offer-overlay {\n position: fixed;\n inset: 0;\n z-index: 120;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n padding: 22px;\n background: rgb(0 0 0 / 48%);\n}\n\n.shared-checkout-special-offer-dialog {\n width: min(100%, 386px);\n box-sizing: border-box;\n border-radius: 14px;\n background: #fff;\n padding: 55px 26px 28px;\n color: #303136;\n text-align: center;\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n.shared-checkout-special-offer-gift {\n display: block;\n width: min(100%, 260px);\n height: auto;\n margin: 0 auto 22px;\n}\n\n.shared-checkout-special-offer-gift--image {\n position: relative;\n width: min(100%, 250px);\n aspect-ratio: 1;\n}\n\n.shared-checkout-special-offer-gift-image {\n display: block;\n width: 100%;\n height: 100%;\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n user-select: none;\n}\n\n.shared-checkout-special-offer-image-discount {\n position: absolute;\n top: 69%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: #1f8f4d;\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 34px;\n font-weight: 900;\n line-height: 1;\n letter-spacing: 0;\n pointer-events: none;\n white-space: nowrap;\n}\n\n.shared-checkout-special-offer-dialog h2 {\n margin: 0;\n color: #303136;\n font-size: 36px;\n font-weight: 900;\n line-height: 1.1;\n letter-spacing: 0;\n}\n\n.shared-checkout-special-offer-dialog p {\n margin: 26px 0 32px;\n color: #77787e;\n font-size: 24px;\n font-weight: 500;\n line-height: 1.18;\n letter-spacing: 0;\n}\n\n.shared-checkout-special-offer-button {\n width: 100%;\n min-height: 76px;\n border: 0;\n border-radius: 12px;\n background: var(--shared-checkout-v2-button-color);\n color: #fff;\n font-size: 23px;\n font-weight: 900;\n line-height: 1;\n letter-spacing: 0;\n cursor: pointer;\n}\n\n@media (max-width: 429px) {\n .shared-checkout-v2-header {\n min-height: 64px;\n }\n\n .shared-checkout-v2-header h2 {\n font-size: 24px;\n }\n\n .shared-checkout-v2-summary {\n padding-inline: 17px;\n }\n\n .shared-checkout-v2-satisfaction {\n font-size: 19px;\n }\n\n .shared-checkout-v2-methods {\n gap: 42px;\n }\n\n .shared-checkout-v2-method strong {\n font-size: 19px;\n }\n\n .shared-checkout-v2-card-panel {\n padding-inline: 32px;\n }\n}\n";