@economist/web-apple-pay 1.7.3 → 1.7.4

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/dist/index.js CHANGED
@@ -76,7 +76,514 @@ function ensureApplePayLogoSymbol() {
76
76
  }
77
77
 
78
78
  // src/templates/apple-pay-modal.template.html
79
- var apple_pay_modal_template_default = '<style>\n .apm-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 97;\n background: rgba(13, 13, 13, 0.7);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--wall-gutter, 2rem);\n box-sizing: border-box;\n }\n\n .apm {\n position: relative;\n background: #fff;\n border-radius: 0.5rem 0.5rem 0 0;\n border: 0.0625rem solid #d9d9d9;\n padding: var(--mb-spacing-lg, 1.5rem);\n width: 25rem;\n max-width: 25rem;\n box-sizing: border-box;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n box-shadow: 0 0.25rem 1rem 0 rgba(13, 13, 13, 0.15);\n }\n\n .apm__close {\n position: absolute;\n top: 1.5rem;\n right: 1.3125rem;\n background: none;\n border: none;\n cursor: pointer;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .apm__close:focus {\n outline: solid 0.125rem var(--focus-border-color, #121212);\n border-radius: 0.25rem;\n }\n\n .apm__offer-name {\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-title-3-size, 1.25rem);\n font-weight: 500;\n color: var(--mb-colour-greyscale-london-5, #0d0d0d);\n line-height: var(--mb-typestyle-title-3-leading, 1.75rem);\n font-style: normal;\n margin: 0 1.5rem 0.5rem 0;\n }\n\n .apm__due-today {\n color: #1a1a1a;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n font-style: normal;\n font-weight: 400;\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n margin: 0 0 0.75rem 0;\n }\n\n .apm__rule {\n border: none;\n border-top: 0.0625rem solid #d9d9d9;\n margin: 0 0 1rem 0;\n }\n\n .apm__terms {\n color: #1a1a1a;\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n font-style: normal;\n font-weight: 400;\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n margin: 0 0 1rem 0;\n }\n\n .apm__terms-bullets {\n list-style: disc outside;\n padding-left: 1.25rem;\n margin: 0 0 0.75rem 0;\n }\n\n .apm__terms-bullets li {\n margin-bottom: 0.375rem;\n }\n\n .apm__terms-legal {\n margin: 0;\n }\n\n .apm__passive-terms {\n font-family: var(--wall-type-system-sans);\n font-size: 0.9375rem;\n color: #0d0d0d;\n line-height: 1.4;\n margin: 0 0 8px 0;\n }\n\n .apm__passive-terms a {\n color: #1a1a1a;\n font-weight: 700;\n text-decoration: underline;\n }\n\n .apm__checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: var(--mb-spacing-sm, 0.5rem);\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: var(--mb-typestyle-label-2-size, 0.9375rem);\n color: var(--mb-colour-greyscale-london-20, #1a1a1a);\n line-height: var(--mb-typestyle-label-2-leading, 1.25rem);\n cursor: pointer;\n margin: 0 0 1.5rem 0;\n }\n\n .apm__checkbox-label--error {\n margin-bottom: 0.25rem;\n }\n\n .apm__checkbox-wrapper {\n position: relative;\n flex-shrink: 0;\n width: 1.25rem;\n height: 1.25rem;\n margin-top: 0.0625rem;\n }\n\n .apm__checkbox-input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n margin: 0;\n z-index: 1;\n }\n\n .apm__checkbox-custom {\n position: absolute;\n top: 0;\n left: 0;\n width: 1.25rem;\n height: 1.25rem;\n pointer-events: none;\n }\n\n .apm__checkbox-custom svg {\n display: none;\n width: 1.25rem;\n height: 1.25rem;\n }\n\n .apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {\n display: block;\n }\n\n .apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {\n display: block;\n }\n\n .apm__checkbox-label--error\n .apm__checkbox-input:not(:checked)\n ~ .apm__checkbox-custom\n .svg-unchecked {\n display: none;\n }\n\n .apm__checkbox-label--error\n .apm__checkbox-input:not(:checked)\n ~ .apm__checkbox-custom\n .svg-error {\n display: block;\n }\n\n .apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {\n outline: solid 0.125rem #c91d42;\n outline-offset: 0.125rem;\n border-radius: 0.25rem;\n }\n\n .apm__checkbox-label a {\n color: #1a1a1a;\n font-weight: 700;\n text-decoration: underline;\n }\n\n .apm__error {\n display: none;\n align-items: center;\n gap: 0.75rem;\n color: var(--mb-colour-greyscale-london-5, #0d0d0d);\n font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));\n font-size: 1.0625rem;\n font-style: normal;\n font-weight: 500;\n line-height: 1.5rem;\n margin-bottom: 1rem;\n }\n\n .apm__error--visible {\n display: flex;\n }\n\n .apm__cta {\n display: flex;\n width: 100%;\n height: 2.75rem;\n padding: 0.375rem 1rem;\n justify-content: center;\n align-items: center;\n gap: 0.375rem;\n border-radius: 0.25rem;\n background: #000;\n border: none;\n cursor: pointer;\n color: #fff;\n text-align: center;\n font-family: var(\n --mb-typeface-sans,\n var(--wall-type-system-sans, system-ui, sans-serif)\n );\n font-size: 1.25rem;\n font-style: normal;\n font-weight: 500;\n line-height: normal;\n }\n\n .apm__cta svg {\n flex-shrink: 0;\n display: block;\n }\n\n @media (min-width: 22.5rem) and (max-width: 37.5rem) {\n .apm {\n width: 24.375rem;\n max-width: 24.375rem;\n }\n }\n\n @media (min-width: 37.5625rem) {\n .apm {\n border-radius: 0.5rem;\n }\n }\n\n @media (max-width: 22.4375rem) {\n .apm {\n width: 20rem;\n max-width: 20rem;\n }\n }\n\n @media (max-width: 26.1875rem) {\n .apm__cta {\n font-size: 1.125rem;\n }\n }\n</style>\n\n<div class="apm-overlay" id="apple-pay-modal-overlay">\n <div\n class="apm"\n role="dialog"\n aria-modal="true"\n aria-labelledby="apple-pay-modal-offer-name"\n id="apple-pay-modal"\n tabindex="-1"\n >\n <button class="apm__close" id="apple-pay-modal-close" aria-label="Close">\n <svg\n aria-hidden="true"\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n >\n <g clip-path="url(#clip0_15712_93054)">\n <rect width="24" height="24" fill="white" fill-opacity="0.01" />\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M0 0H24V24H0V0Z"\n fill="white"\n fill-opacity="0.01"\n />\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M18.75 6.60964L17.3904 5.25L12 10.6404L6.60964 5.25L5.25 6.60964L10.6404 12L5.25 17.3904L6.60964 18.75L12 13.3596L17.3904 18.75L18.75 17.3904L13.3596 12L18.75 6.60964Z"\n fill="#333333"\n />\n </g>\n <defs>\n <clipPath id="clip0_15712_93054">\n <rect width="24" height="24" fill="white" />\n </clipPath>\n </defs>\n </svg>\n </button>\n <p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>\n <p class="apm__due-today" id="apple-pay-modal-due-today"></p>\n <hr class="apm__rule" />\n <div class="apm__terms" id="apple-pay-modal-terms"></div>\n <p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>\n <label\n class="apm__checkbox-label"\n id="apple-pay-modal-checkbox-label"\n for="apple-pay-modal-checkbox"\n >\n <div class="apm__checkbox-wrapper">\n <input\n class="apm__checkbox-input"\n type="checkbox"\n id="apple-pay-modal-checkbox"\n />\n <span class="apm__checkbox-custom">\n <svg\n aria-hidden="true"\n class="svg-unchecked"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"\n fill="white"\n stroke="#595959"\n />\n </svg>\n <svg\n aria-hidden="true"\n class="svg-checked"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <g clip-path="url(#clip0_20014_9555)">\n <path\n d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"\n fill="#333333"\n />\n <path\n d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"\n fill="white"\n />\n </g>\n <defs>\n <clipPath id="clip0_20014_9555">\n <path\n d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"\n fill="white"\n />\n </clipPath>\n </defs>\n </svg>\n <svg\n aria-hidden="true"\n class="svg-error"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"\n fill="white"\n stroke="#C91D42"\n stroke-width="2"\n />\n </svg>\n </span>\n </div>\n <span id="apple-pay-modal-checkbox-text"></span>\n </label>\n <div class="apm__error" id="apple-pay-modal-error" role="alert">\n <svg\n aria-hidden="true"\n width="20"\n height="20"\n viewBox="0 0 20 20"\n fill="none"\n xmlns="http://www.w3.org/2000/svg"\n >\n <path\n fill-rule="evenodd"\n clip-rule="evenodd"\n d="M10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10ZM11 13C11 13.5523 10.5523 14 10 14C9.44772 14 9 13.5523 9 13C9 12.4477 9.44772 12 10 12C10.5523 12 11 12.4477 11 13ZM10 6C10.5523 6 11 6.44772 11 7V10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10V7C9 6.44772 9.44772 6 10 6Z"\n fill="#C91D42"\n />\n </svg>\n Please accept the terms to continue\n </div>\n <button class="apm__cta" id="apple-pay-modal-cta">\n Continue with\n <svg width="51" height="22" aria-label="Apple Pay" role="img">\n <use href="#apple-pay-logo" />\n </svg>\n </button>\n </div>\n</div>\n\n';
79
+ var apple_pay_modal_template_default = `<style>
80
+ .apm-overlay {
81
+ position: fixed;
82
+ top: 0;
83
+ left: 0;
84
+ width: 100%;
85
+ height: 100%;
86
+ z-index: 97;
87
+ background: rgba(13, 13, 13, 0.7);
88
+ display: flex;
89
+ align-items: center;
90
+ justify-content: center;
91
+ padding: var(--wall-gutter, 2rem);
92
+ box-sizing: border-box;
93
+ }
94
+
95
+ .apm {
96
+ position: relative;
97
+ background: #fff;
98
+ border-radius: 0.5rem 0.5rem 0 0;
99
+ border: 0.0625rem solid #d9d9d9;
100
+ padding: var(--mb-spacing-lg, 1.5rem);
101
+ width: 25rem;
102
+ max-width: 25rem;
103
+ box-sizing: border-box;
104
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
105
+ box-shadow: 0 0.25rem 1rem 0 rgba(13, 13, 13, 0.15);
106
+ }
107
+
108
+ .apm__close {
109
+ position: absolute;
110
+ top: 1.5rem;
111
+ right: 1.3125rem;
112
+ background: none;
113
+ border: none;
114
+ cursor: pointer;
115
+ padding: 0;
116
+ display: flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ }
120
+
121
+ .apm__close:focus {
122
+ outline: solid 0.125rem var(--focus-border-color, #121212);
123
+ border-radius: 0.25rem;
124
+ }
125
+
126
+ .apm__offer-name {
127
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
128
+ font-size: var(--mb-typestyle-title-3-size, 1.25rem);
129
+ font-weight: 500;
130
+ color: var(--mb-colour-greyscale-london-5, #0d0d0d);
131
+ line-height: var(--mb-typestyle-title-3-leading, 1.75rem);
132
+ font-style: normal;
133
+ margin: 0 1.5rem 0.5rem 0;
134
+ }
135
+
136
+ .apm__due-today {
137
+ color: #1a1a1a;
138
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
139
+ font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
140
+ font-style: normal;
141
+ font-weight: 400;
142
+ line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
143
+ margin: 0 0 0.75rem 0;
144
+ }
145
+
146
+ .apm__rule {
147
+ border: none;
148
+ border-top: 0.0625rem solid #d9d9d9;
149
+ margin: 0 0 1rem 0;
150
+ }
151
+
152
+ .apm__terms {
153
+ color: #1a1a1a;
154
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
155
+ font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
156
+ font-style: normal;
157
+ font-weight: 400;
158
+ line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
159
+ margin: 0 0 1rem 0;
160
+ }
161
+
162
+ .apm__terms-bullets {
163
+ list-style: disc outside;
164
+ padding-left: 1.25rem;
165
+ margin: 0 0 0.75rem 0;
166
+ }
167
+
168
+ .apm__terms-bullets li {
169
+ margin-bottom: 0.375rem;
170
+ }
171
+
172
+ .apm__terms-legal {
173
+ margin: 0;
174
+ }
175
+
176
+ .apm__passive-terms {
177
+ font-family: var(--wall-type-system-sans);
178
+ font-size: 0.9375rem;
179
+ color: #0d0d0d;
180
+ line-height: 1.4;
181
+ margin: 0 0 8px 0;
182
+ }
183
+
184
+ .apm__passive-terms a {
185
+ color: #1a1a1a;
186
+ font-weight: 700;
187
+ text-decoration: underline;
188
+ }
189
+
190
+ .apm__checkbox-label {
191
+ display: flex;
192
+ align-items: flex-start;
193
+ gap: var(--mb-spacing-sm, 0.5rem);
194
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
195
+ font-size: var(--mb-typestyle-label-2-size, 0.9375rem);
196
+ color: var(--mb-colour-greyscale-london-20, #1a1a1a);
197
+ line-height: var(--mb-typestyle-label-2-leading, 1.25rem);
198
+ cursor: pointer;
199
+ margin: 0 0 1.5rem 0;
200
+ }
201
+
202
+ .apm__checkbox-label--error {
203
+ margin-bottom: 0.25rem;
204
+ }
205
+
206
+ .apm__checkbox-wrapper {
207
+ position: relative;
208
+ flex-shrink: 0;
209
+ width: 1.25rem;
210
+ height: 1.25rem;
211
+ margin-top: 0.0625rem;
212
+ }
213
+
214
+ .apm__checkbox-input {
215
+ position: absolute;
216
+ opacity: 0;
217
+ width: 100%;
218
+ height: 100%;
219
+ cursor: pointer;
220
+ margin: 0;
221
+ z-index: 1;
222
+ }
223
+
224
+ .apm__checkbox-custom {
225
+ position: absolute;
226
+ top: 0;
227
+ left: 0;
228
+ width: 1.25rem;
229
+ height: 1.25rem;
230
+ pointer-events: none;
231
+ }
232
+
233
+ .apm__checkbox-custom svg {
234
+ display: none;
235
+ width: 1.25rem;
236
+ height: 1.25rem;
237
+ }
238
+
239
+ .apm__checkbox-input:not(:checked) ~ .apm__checkbox-custom .svg-unchecked {
240
+ display: block;
241
+ }
242
+
243
+ .apm__checkbox-input:checked ~ .apm__checkbox-custom .svg-checked {
244
+ display: block;
245
+ }
246
+
247
+ .apm__checkbox-label--error
248
+ .apm__checkbox-input:not(:checked)
249
+ ~ .apm__checkbox-custom
250
+ .svg-unchecked {
251
+ display: none;
252
+ }
253
+
254
+ .apm__checkbox-label--error
255
+ .apm__checkbox-input:not(:checked)
256
+ ~ .apm__checkbox-custom
257
+ .svg-error {
258
+ display: block;
259
+ }
260
+
261
+ .apm__checkbox-input:focus-visible ~ .apm__checkbox-custom {
262
+ outline: solid 0.125rem #c91d42;
263
+ outline-offset: 0.125rem;
264
+ border-radius: 0.25rem;
265
+ }
266
+
267
+ .apm__checkbox-label a {
268
+ color: #1a1a1a;
269
+ font-weight: 700;
270
+ text-decoration: underline;
271
+ }
272
+
273
+ .apm__error {
274
+ display: none;
275
+ align-items: center;
276
+ gap: 0.75rem;
277
+ color: var(--mb-colour-greyscale-london-5, #0d0d0d);
278
+ font-family: var(--mb-typeface-sans, var(--wall-type-system-sans));
279
+ font-size: 1.0625rem;
280
+ font-style: normal;
281
+ font-weight: 500;
282
+ line-height: 1.5rem;
283
+ margin-bottom: 1rem;
284
+ }
285
+
286
+ .apm__error--visible {
287
+ display: flex;
288
+ }
289
+
290
+ .apm__cta {
291
+ display: flex;
292
+ width: 100%;
293
+ height: 2.75rem;
294
+ padding: 0.375rem 1rem;
295
+ justify-content: center;
296
+ align-items: center;
297
+ gap: 0.375rem;
298
+ border-radius: 0.25rem;
299
+ background: #000;
300
+ border: none;
301
+ cursor: pointer;
302
+ color: #fff;
303
+ text-align: center;
304
+ font-family: var(
305
+ --mb-typeface-sans,
306
+ var(--wall-type-system-sans, system-ui, sans-serif)
307
+ );
308
+ font-size: 1.25rem;
309
+ font-style: normal;
310
+ font-weight: 500;
311
+ line-height: normal;
312
+ }
313
+
314
+ .apm__cta:disabled {
315
+ cursor: not-allowed;
316
+ }
317
+
318
+ .apm__cta[aria-busy="true"] {
319
+ position: relative;
320
+ cursor: not-allowed;
321
+ }
322
+
323
+ .apm__cta[aria-busy="true"] > * {
324
+ visibility: hidden;
325
+ }
326
+
327
+ .apm__cta[aria-busy="true"]::after {
328
+ content: '';
329
+ position: absolute;
330
+ left: 50%;
331
+ top: 50%;
332
+ margin-left: -0.625rem;
333
+ margin-top: -0.625rem;
334
+ width: 1.25rem;
335
+ height: 1.25rem;
336
+ border: 2px solid rgba(255, 255, 255, 0.2);
337
+ border-top-color: #fff;
338
+ border-radius: 50%;
339
+ animation: apm-cta-spinner 0.8s linear infinite;
340
+ }
341
+
342
+ @keyframes apm-cta-spinner {
343
+ to {
344
+ transform: rotate(360deg);
345
+ }
346
+ }
347
+
348
+ .apm__cta svg {
349
+ flex-shrink: 0;
350
+ display: block;
351
+ }
352
+
353
+ @media (min-width: 22.5rem) and (max-width: 37.5rem) {
354
+ .apm {
355
+ width: 24.375rem;
356
+ max-width: 24.375rem;
357
+ }
358
+ }
359
+
360
+ @media (min-width: 37.5625rem) {
361
+ .apm {
362
+ border-radius: 0.5rem;
363
+ }
364
+ }
365
+
366
+ @media (max-width: 22.4375rem) {
367
+ .apm {
368
+ width: 20rem;
369
+ max-width: 20rem;
370
+ }
371
+ }
372
+
373
+ @media (max-width: 26.1875rem) {
374
+ .apm__cta {
375
+ font-size: 1.125rem;
376
+ }
377
+ }
378
+ </style>
379
+
380
+ <div class="apm-overlay" id="apple-pay-modal-overlay">
381
+ <div
382
+ class="apm"
383
+ role="dialog"
384
+ aria-modal="true"
385
+ aria-labelledby="apple-pay-modal-offer-name"
386
+ id="apple-pay-modal"
387
+ tabindex="-1"
388
+ >
389
+ <button class="apm__close" id="apple-pay-modal-close" aria-label="Close">
390
+ <svg
391
+ aria-hidden="true"
392
+ xmlns="http://www.w3.org/2000/svg"
393
+ width="24"
394
+ height="24"
395
+ viewBox="0 0 24 24"
396
+ fill="none"
397
+ >
398
+ <g clip-path="url(#clip0_15712_93054)">
399
+ <rect width="24" height="24" fill="white" fill-opacity="0.01" />
400
+ <path
401
+ fill-rule="evenodd"
402
+ clip-rule="evenodd"
403
+ d="M0 0H24V24H0V0Z"
404
+ fill="white"
405
+ fill-opacity="0.01"
406
+ />
407
+ <path
408
+ fill-rule="evenodd"
409
+ clip-rule="evenodd"
410
+ d="M18.75 6.60964L17.3904 5.25L12 10.6404L6.60964 5.25L5.25 6.60964L10.6404 12L5.25 17.3904L6.60964 18.75L12 13.3596L17.3904 18.75L18.75 17.3904L13.3596 12L18.75 6.60964Z"
411
+ fill="#333333"
412
+ />
413
+ </g>
414
+ <defs>
415
+ <clipPath id="clip0_15712_93054">
416
+ <rect width="24" height="24" fill="white" />
417
+ </clipPath>
418
+ </defs>
419
+ </svg>
420
+ </button>
421
+ <p class="apm__offer-name" id="apple-pay-modal-offer-name"></p>
422
+ <p class="apm__due-today" id="apple-pay-modal-due-today"></p>
423
+ <hr class="apm__rule" />
424
+ <div class="apm__terms" id="apple-pay-modal-terms"></div>
425
+ <p class="apm__passive-terms" id="apple-pay-modal-passive-terms"></p>
426
+ <label
427
+ class="apm__checkbox-label"
428
+ id="apple-pay-modal-checkbox-label"
429
+ for="apple-pay-modal-checkbox"
430
+ >
431
+ <div class="apm__checkbox-wrapper">
432
+ <input
433
+ class="apm__checkbox-input"
434
+ type="checkbox"
435
+ id="apple-pay-modal-checkbox"
436
+ />
437
+ <span class="apm__checkbox-custom">
438
+ <svg
439
+ aria-hidden="true"
440
+ class="svg-unchecked"
441
+ width="24"
442
+ height="24"
443
+ viewBox="0 0 24 24"
444
+ fill="none"
445
+ xmlns="http://www.w3.org/2000/svg"
446
+ >
447
+ <path
448
+ d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"
449
+ fill="white"
450
+ stroke="#595959"
451
+ />
452
+ </svg>
453
+ <svg
454
+ aria-hidden="true"
455
+ class="svg-checked"
456
+ width="24"
457
+ height="24"
458
+ viewBox="0 0 24 24"
459
+ fill="none"
460
+ xmlns="http://www.w3.org/2000/svg"
461
+ >
462
+ <g clip-path="url(#clip0_20014_9555)">
463
+ <path
464
+ d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"
465
+ fill="#333333"
466
+ />
467
+ <path
468
+ d="M10.2857 17L6 12.6814L7.20857 11.4635L10.2857 14.5557L16.7914 8L18 9.22649L10.2857 17Z"
469
+ fill="white"
470
+ />
471
+ </g>
472
+ <defs>
473
+ <clipPath id="clip0_20014_9555">
474
+ <path
475
+ d="M2 6C2 3.79086 3.79086 2 6 2H18C20.2091 2 22 3.79086 22 6V18C22 20.2091 20.2091 22 18 22H6C3.79086 22 2 20.2091 2 18V6Z"
476
+ fill="white"
477
+ />
478
+ </clipPath>
479
+ </defs>
480
+ </svg>
481
+ <svg
482
+ aria-hidden="true"
483
+ class="svg-error"
484
+ width="24"
485
+ height="24"
486
+ viewBox="0 0 24 24"
487
+ fill="none"
488
+ xmlns="http://www.w3.org/2000/svg"
489
+ >
490
+ <path
491
+ d="M6 2.5H18C19.933 2.5 21.5 4.067 21.5 6V18C21.5 19.933 19.933 21.5 18 21.5H6C4.067 21.5 2.5 19.933 2.5 18V6C2.5 4.067 4.067 2.5 6 2.5Z"
492
+ fill="white"
493
+ stroke="#C91D42"
494
+ stroke-width="2"
495
+ />
496
+ </svg>
497
+ </span>
498
+ </div>
499
+ <span id="apple-pay-modal-checkbox-text"></span>
500
+ </label>
501
+ <div class="apm__error" id="apple-pay-modal-error" role="alert">
502
+ <svg
503
+ aria-hidden="true"
504
+ width="20"
505
+ height="20"
506
+ viewBox="0 0 20 20"
507
+ fill="none"
508
+ xmlns="http://www.w3.org/2000/svg"
509
+ >
510
+ <path
511
+ fill-rule="evenodd"
512
+ clip-rule="evenodd"
513
+ d="M10 2C5.58172 2 2 5.58172 2 10C2 14.4183 5.58172 18 10 18C14.4183 18 18 14.4183 18 10C18 5.58172 14.4183 2 10 2ZM0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10ZM11 13C11 13.5523 10.5523 14 10 14C9.44772 14 9 13.5523 9 13C9 12.4477 9.44772 12 10 12C10.5523 12 11 12.4477 11 13ZM10 6C10.5523 6 11 6.44772 11 7V10C11 10.5523 10.5523 11 10 11C9.44772 11 9 10.5523 9 10V7C9 6.44772 9.44772 6 10 6Z"
514
+ fill="#C91D42"
515
+ />
516
+ </svg>
517
+ Please accept the terms to continue
518
+ </div>
519
+ <button class="apm__cta" id="apple-pay-modal-cta" aria-label="Continue with Apple Pay">
520
+ <span class="apm__cta-content">
521
+ Continue with
522
+ <svg width="51" height="22" aria-hidden="true" role="img">
523
+ <use href="#apple-pay-logo" />
524
+ </svg>
525
+ </span>
526
+ </button>
527
+ </div>
528
+ </div>
529
+
530
+ `;
531
+
532
+ // src/clients/payment-checkout/config.ts
533
+ var runtimeConfig = null;
534
+ var configureApplePay = (config) => {
535
+ runtimeConfig = {
536
+ ...config
537
+ };
538
+ };
539
+ var getApplePayConfig = () => runtimeConfig;
540
+
541
+ // src/utils/recaptcha.ts
542
+ var loadRecaptchaScript = (siteKey) => {
543
+ return new Promise((resolve, reject) => {
544
+ if (typeof grecaptcha !== "undefined") return resolve();
545
+ const existingScript = document.querySelector(
546
+ 'script[src*="recaptcha/api.js"]'
547
+ );
548
+ if (existingScript) {
549
+ existingScript.addEventListener("load", () => resolve());
550
+ existingScript.addEventListener(
551
+ "error",
552
+ () => reject(new Error("Failed to load existing reCAPTCHA script"))
553
+ );
554
+ return;
555
+ }
556
+ const script = document.createElement("script");
557
+ script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
558
+ script.async = true;
559
+ script.defer = true;
560
+ script.onload = () => resolve();
561
+ script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
562
+ document.head.appendChild(script);
563
+ });
564
+ };
565
+ var getRecaptchaToken = async (action) => {
566
+ const siteKey = getApplePayConfig()?.recaptchaSiteKey;
567
+ if (!siteKey) {
568
+ throw new Error(
569
+ "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
570
+ );
571
+ }
572
+ await loadRecaptchaScript(siteKey);
573
+ return new Promise((resolve, reject) => {
574
+ grecaptcha.ready(() => {
575
+ grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
576
+ });
577
+ });
578
+ };
579
+ var getPurchaseRecaptchaTokens = async () => {
580
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
581
+ getRecaptchaToken("checkEligibility"),
582
+ getRecaptchaToken("newBasket"),
583
+ getRecaptchaToken("registerUser")
584
+ ]);
585
+ return { checkEligibility, newBasket, registerUser };
586
+ };
80
587
 
81
588
  // src/apple-pay-modal.ts
82
589
  function getRenewalDateText(unit, duration) {
@@ -128,6 +635,7 @@ function getOfferTypeText(offerType) {
128
635
  }
129
636
  var TERMS_LINK = '<a href="https://www.economistgroup.com/terms-of-use" target="_blank" rel="noopener noreferrer">Terms and Conditions</a>';
130
637
  var PRIVACY_LINK = '<a href="https://www.economistgroup.com/privacy-policy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>';
638
+ var MSG_RECAPTCHA_LOAD_ERROR = "Something went wrong. Please close and try again.";
131
639
  function getCheckboxTermsHtml(isNYT, isLoggedIn, autoRenewal) {
132
640
  const autoRenewalClause = autoRenewal ? " and auto-renewal terms above," : "";
133
641
  if (isNYT) {
@@ -297,6 +805,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
297
805
  #country = "";
298
806
  #triggerElement = null;
299
807
  #keyHandler = null;
808
+ #recaptchaTokens = null;
809
+ #recaptchaTokensPromise = null;
810
+ /**
811
+ * Synchronous callback invoked directly from the CTA click handler once the
812
+ * user confirms. The caller (ApplePayButton) must call startApplePaySession
813
+ * inside this callback to preserve the browser's user-gesture chain — Safari
814
+ * requires new ApplePaySession() to execute within the original click stack.
815
+ *
816
+ * reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
817
+ * until the token pre-fetch resolves, so this callback is never reached
818
+ * without valid tokens.
819
+ */
820
+ onConfirm = null;
300
821
  set offer(value) {
301
822
  this.#offer = value;
302
823
  }
@@ -391,27 +912,57 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
391
912
  }
392
913
  });
393
914
  }
915
+ if (this.#recaptchaTokensPromise) {
916
+ if (cta) {
917
+ cta.setAttribute("disabled", "");
918
+ cta.setAttribute("aria-disabled", "true");
919
+ cta.setAttribute("aria-busy", "true");
920
+ }
921
+ this.#recaptchaTokensPromise.then((tokens) => {
922
+ this.#recaptchaTokens = tokens;
923
+ if (cta) {
924
+ cta.removeAttribute("disabled");
925
+ cta.removeAttribute("aria-disabled");
926
+ cta.removeAttribute("aria-busy");
927
+ }
928
+ }).catch(() => {
929
+ console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
930
+ if (cta) {
931
+ cta.removeAttribute("aria-busy");
932
+ }
933
+ const existingError = this.querySelector("#apple-pay-modal-error");
934
+ if (existingError) {
935
+ const icon = existingError.querySelector("svg");
936
+ existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
937
+ if (icon) existingError.prepend(icon);
938
+ existingError.classList.add("apm__error--visible");
939
+ } else {
940
+ const errorNotice = document.createElement("div");
941
+ errorNotice.setAttribute("role", "alert");
942
+ errorNotice.className = "apm__error apm__error--visible";
943
+ errorNotice.textContent = MSG_RECAPTCHA_LOAD_ERROR;
944
+ cta?.insertAdjacentElement("beforebegin", errorNotice);
945
+ }
946
+ });
947
+ }
394
948
  cta?.addEventListener("click", () => {
395
949
  if (isUS && checkbox && !checkbox.checked) {
396
950
  errorElement?.classList.add("apm__error--visible");
397
951
  checkboxLabel?.classList.add("apm__checkbox-label--error");
398
952
  return;
399
953
  }
400
- this.dispatchEvent(
401
- new CustomEvent("apple-pay-confirmed", {
402
- bubbles: true,
403
- composed: true,
404
- detail: { skuId: offer.sku_id, country }
405
- })
406
- );
407
- this.close();
954
+ if (this.#recaptchaTokens) {
955
+ this.onConfirm?.(this.#recaptchaTokens);
956
+ this.close();
957
+ }
408
958
  });
409
959
  this.querySelector("#apple-pay-modal-close")?.addEventListener(
410
960
  "click",
411
961
  () => this.close()
412
962
  );
413
963
  }
414
- open() {
964
+ open(recaptchaTokensPromise) {
965
+ this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
415
966
  this.#triggerElement = document.activeElement;
416
967
  document.body.appendChild(this);
417
968
  this.#keyHandler = (event) => {
@@ -524,15 +1075,6 @@ var apple_pay_button_template_default = `<style>
524
1075
  </div>
525
1076
  `;
526
1077
 
527
- // src/clients/payment-checkout/config.ts
528
- var runtimeConfig = null;
529
- var configureApplePay = (config) => {
530
- runtimeConfig = {
531
- ...config
532
- };
533
- };
534
- var getApplePayConfig = () => runtimeConfig;
535
-
536
1078
  // src/clients/payment-checkout/detects.ts
537
1079
  var isAppleDeviceOrSafari = () => {
538
1080
  const isIOSOrMacTouchDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent);
@@ -565,7 +1107,8 @@ var isApplePayAvailable = async () => {
565
1107
  );
566
1108
  return false;
567
1109
  }
568
- return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1110
+ const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1111
+ return hasActiveCard;
569
1112
  } catch (error) {
570
1113
  console.error("Error checking Apple Pay active card status:", error);
571
1114
  return false;
@@ -694,53 +1237,6 @@ var redirectToCheckoutFallback = (params) => {
694
1237
  return url.pathname + url.search;
695
1238
  };
696
1239
 
697
- // src/utils/recaptcha.ts
698
- var loadRecaptchaScript = (siteKey) => {
699
- return new Promise((resolve, reject) => {
700
- if (typeof grecaptcha !== "undefined") return resolve();
701
- const existingScript = document.querySelector(
702
- 'script[src*="recaptcha/api.js"]'
703
- );
704
- if (existingScript) {
705
- existingScript.addEventListener("load", () => resolve());
706
- existingScript.addEventListener(
707
- "error",
708
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
709
- );
710
- return;
711
- }
712
- const script = document.createElement("script");
713
- script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
714
- script.async = true;
715
- script.defer = true;
716
- script.onload = () => resolve();
717
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
718
- document.head.appendChild(script);
719
- });
720
- };
721
- var getRecaptchaToken = async (action) => {
722
- const siteKey = getApplePayConfig()?.recaptchaSiteKey;
723
- if (!siteKey) {
724
- throw new Error(
725
- "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
726
- );
727
- }
728
- await loadRecaptchaScript(siteKey);
729
- return new Promise((resolve, reject) => {
730
- grecaptcha.ready(() => {
731
- grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
732
- });
733
- });
734
- };
735
- var getPurchaseRecaptchaTokens = async () => {
736
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
737
- getRecaptchaToken("checkEligibility"),
738
- getRecaptchaToken("newBasket"),
739
- getRecaptchaToken("registerUser")
740
- ]);
741
- return { checkEligibility, newBasket, registerUser };
742
- };
743
-
744
1240
  // src/utils/expressCheckoutTracking.ts
745
1241
  var EXPRESS_CHECKOUT_EVENTS = {
746
1242
  /** Wallet button displayed */
@@ -853,7 +1349,8 @@ async function handleMerchantValidation(event, session, config) {
853
1349
  return;
854
1350
  }
855
1351
  session.completeMerchantValidation(response.merchantSession);
856
- } catch {
1352
+ } catch (err) {
1353
+ console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
857
1354
  session.abort();
858
1355
  redirectToFallbackCheckout(config);
859
1356
  }
@@ -886,7 +1383,8 @@ function startApplePaySession(config) {
886
1383
  };
887
1384
  trackWalletPaymentSheetOpen(config.skuId);
888
1385
  session.begin();
889
- } catch {
1386
+ } catch (err) {
1387
+ console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
890
1388
  redirectToFallbackCheckout(config);
891
1389
  }
892
1390
  }
@@ -1074,6 +1572,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1074
1572
  const result = await performPurchase({
1075
1573
  applePayToken: event.payment.token,
1076
1574
  skuId: config.skuId,
1575
+ currency: config.currency,
1077
1576
  billingContact: event.payment.billingContact,
1078
1577
  ...event.payment.shippingContact && {
1079
1578
  shippingContact: event.payment.shippingContact
@@ -1424,7 +1923,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1424
1923
  #returnUrl = "";
1425
1924
  #supportedBillingCountries = [];
1426
1925
  #entryPoint = "";
1427
- #recaptchaTokens = null;
1926
+ #recaptchaTokensPromise = null;
1428
1927
  // ─── Public API ─────────────────────────────────────────────────────────────
1429
1928
  get offer() {
1430
1929
  return this.#offer;
@@ -1489,6 +1988,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1489
1988
  this.#paymentOptions = null;
1490
1989
  this.#returnUrl = "";
1491
1990
  this.#supportedBillingCountries = [];
1991
+ this.#recaptchaTokensPromise = null;
1492
1992
  this.querySelector(SEL_CONTAINER)?.remove();
1493
1993
  }
1494
1994
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -1502,7 +2002,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1502
2002
  this.#computeBillingCountries();
1503
2003
  if (await this.#fetchAndCacheOptions()) return;
1504
2004
  this.#finishLoading();
1505
- } catch {
2005
+ } catch (err) {
2006
+ console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
1506
2007
  this.style.display = "none";
1507
2008
  this.querySelector(SEL_CONTAINER)?.remove();
1508
2009
  } finally {
@@ -1583,16 +2084,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1583
2084
  if (button.classList.contains("wap-loading")) return;
1584
2085
  this.#openModal();
1585
2086
  });
1586
- document.addEventListener("apple-pay-confirmed", (event) => {
1587
- const { skuId, country } = event.detail;
1588
- this.#initiateApplePay(skuId, country);
1589
- }, { once: true });
1590
2087
  }
1591
2088
  #finishLoading() {
1592
2089
  const button = this.querySelector(SEL_BUTTON);
1593
2090
  if (button) {
1594
2091
  button.classList.remove("wap-loading");
1595
2092
  this.#updateDisabledState();
2093
+ this.#scheduleRecaptchaTokens();
1596
2094
  trackExpressWalletImpression(this.#offer.sku_id, {
1597
2095
  entryPoint: this.#entryPoint,
1598
2096
  country: this.#country
@@ -1620,10 +2118,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1620
2118
  return;
1621
2119
  }
1622
2120
  trackExpressWalletClick(this.#offer.sku_id);
1623
- getPurchaseRecaptchaTokens().then((tokens) => {
1624
- this.#recaptchaTokens = tokens;
1625
- }).catch(() => {
1626
- });
1627
2121
  ApplePayModal.define();
1628
2122
  const modal = document.createElement(ApplePayModal.tag);
1629
2123
  modal.offer = this.#offer;
@@ -1631,7 +2125,30 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1631
2125
  if (this.#sessionData?.loggedIn) {
1632
2126
  modal.dataset.loggedIn = "true";
1633
2127
  }
1634
- modal.open();
2128
+ const skuId = this.#offer.sku_id;
2129
+ const country = this.#country;
2130
+ modal.onConfirm = (recaptchaTokens) => {
2131
+ this.#initiateApplePay(skuId, country, recaptchaTokens);
2132
+ this.#scheduleRecaptchaTokens();
2133
+ };
2134
+ modal.open(this.#recaptchaTokensPromise);
2135
+ }
2136
+ /**
2137
+ * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2138
+ * If the fetch rejects, the field is cleared so the next `modal.open()` call
2139
+ * falls back to a new attempt via the modal's own null-fallback path — preventing
2140
+ * a single transient failure from permanently disabling the CTA on all retries.
2141
+ * The identity guard prevents a late rejection from clobbering a newer attempt.
2142
+ */
2143
+ #scheduleRecaptchaTokens() {
2144
+ const attempt = getPurchaseRecaptchaTokens();
2145
+ attempt.catch((err) => {
2146
+ console.error("[web-apple-pay] reCAPTCHA token pre-fetch failed; will retry on modal open", err);
2147
+ if (this.#recaptchaTokensPromise === attempt) {
2148
+ this.#recaptchaTokensPromise = null;
2149
+ }
2150
+ });
2151
+ this.#recaptchaTokensPromise = attempt;
1635
2152
  }
1636
2153
  async #fetchSession() {
1637
2154
  try {
@@ -1667,6 +2184,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1667
2184
  onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
1668
2185
  skuId,
1669
2186
  country,
2187
+ currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1670
2188
  returnUrl: this.#returnUrl,
1671
2189
  queryString: buildQueryString(),
1672
2190
  supportedBillingCountries: this.#supportedBillingCountries,
@@ -1674,11 +2192,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1674
2192
  })
1675
2193
  };
1676
2194
  }
1677
- async #initiateApplePay(skuId, country) {
2195
+ #initiateApplePay(skuId, country, recaptchaTokens) {
1678
2196
  try {
1679
2197
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1680
2198
  const paymentOptions = this.#paymentOptions;
1681
- const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1682
2199
  startApplePaySession(
1683
2200
  this.#buildSessionParams(
1684
2201
  skuId,