@economist/web-apple-pay 1.7.2 → 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.
@@ -76,7 +76,509 @@ 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 getApplePayConfig = () => runtimeConfig;
535
+
536
+ // src/utils/recaptcha.ts
537
+ var loadRecaptchaScript = (siteKey) => {
538
+ return new Promise((resolve, reject) => {
539
+ if (typeof grecaptcha !== "undefined") return resolve();
540
+ const existingScript = document.querySelector(
541
+ 'script[src*="recaptcha/api.js"]'
542
+ );
543
+ if (existingScript) {
544
+ existingScript.addEventListener("load", () => resolve());
545
+ existingScript.addEventListener(
546
+ "error",
547
+ () => reject(new Error("Failed to load existing reCAPTCHA script"))
548
+ );
549
+ return;
550
+ }
551
+ const script = document.createElement("script");
552
+ script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
553
+ script.async = true;
554
+ script.defer = true;
555
+ script.onload = () => resolve();
556
+ script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
557
+ document.head.appendChild(script);
558
+ });
559
+ };
560
+ var getRecaptchaToken = async (action) => {
561
+ const siteKey = getApplePayConfig()?.recaptchaSiteKey;
562
+ if (!siteKey) {
563
+ throw new Error(
564
+ "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
565
+ );
566
+ }
567
+ await loadRecaptchaScript(siteKey);
568
+ return new Promise((resolve, reject) => {
569
+ grecaptcha.ready(() => {
570
+ grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
571
+ });
572
+ });
573
+ };
574
+ var getPurchaseRecaptchaTokens = async () => {
575
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
576
+ getRecaptchaToken("checkEligibility"),
577
+ getRecaptchaToken("newBasket"),
578
+ getRecaptchaToken("registerUser")
579
+ ]);
580
+ return { checkEligibility, newBasket, registerUser };
581
+ };
80
582
 
81
583
  // src/apple-pay-modal.ts
82
584
  function getRenewalDateText(unit, duration) {
@@ -128,6 +630,7 @@ function getOfferTypeText(offerType) {
128
630
  }
129
631
  var TERMS_LINK = '<a href="https://www.economistgroup.com/terms-of-use" target="_blank" rel="noopener noreferrer">Terms and Conditions</a>';
130
632
  var PRIVACY_LINK = '<a href="https://www.economistgroup.com/privacy-policy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>';
633
+ var MSG_RECAPTCHA_LOAD_ERROR = "Something went wrong. Please close and try again.";
131
634
  function getCheckboxTermsHtml(isNYT, isLoggedIn, autoRenewal) {
132
635
  const autoRenewalClause = autoRenewal ? " and auto-renewal terms above," : "";
133
636
  if (isNYT) {
@@ -297,6 +800,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
297
800
  #country = "";
298
801
  #triggerElement = null;
299
802
  #keyHandler = null;
803
+ #recaptchaTokens = null;
804
+ #recaptchaTokensPromise = null;
805
+ /**
806
+ * Synchronous callback invoked directly from the CTA click handler once the
807
+ * user confirms. The caller (ApplePayButton) must call startApplePaySession
808
+ * inside this callback to preserve the browser's user-gesture chain — Safari
809
+ * requires new ApplePaySession() to execute within the original click stack.
810
+ *
811
+ * reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
812
+ * until the token pre-fetch resolves, so this callback is never reached
813
+ * without valid tokens.
814
+ */
815
+ onConfirm = null;
300
816
  set offer(value) {
301
817
  this.#offer = value;
302
818
  }
@@ -391,27 +907,57 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
391
907
  }
392
908
  });
393
909
  }
910
+ if (this.#recaptchaTokensPromise) {
911
+ if (cta) {
912
+ cta.setAttribute("disabled", "");
913
+ cta.setAttribute("aria-disabled", "true");
914
+ cta.setAttribute("aria-busy", "true");
915
+ }
916
+ this.#recaptchaTokensPromise.then((tokens) => {
917
+ this.#recaptchaTokens = tokens;
918
+ if (cta) {
919
+ cta.removeAttribute("disabled");
920
+ cta.removeAttribute("aria-disabled");
921
+ cta.removeAttribute("aria-busy");
922
+ }
923
+ }).catch(() => {
924
+ console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
925
+ if (cta) {
926
+ cta.removeAttribute("aria-busy");
927
+ }
928
+ const existingError = this.querySelector("#apple-pay-modal-error");
929
+ if (existingError) {
930
+ const icon = existingError.querySelector("svg");
931
+ existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
932
+ if (icon) existingError.prepend(icon);
933
+ existingError.classList.add("apm__error--visible");
934
+ } else {
935
+ const errorNotice = document.createElement("div");
936
+ errorNotice.setAttribute("role", "alert");
937
+ errorNotice.className = "apm__error apm__error--visible";
938
+ errorNotice.textContent = MSG_RECAPTCHA_LOAD_ERROR;
939
+ cta?.insertAdjacentElement("beforebegin", errorNotice);
940
+ }
941
+ });
942
+ }
394
943
  cta?.addEventListener("click", () => {
395
944
  if (isUS && checkbox && !checkbox.checked) {
396
945
  errorElement?.classList.add("apm__error--visible");
397
946
  checkboxLabel?.classList.add("apm__checkbox-label--error");
398
947
  return;
399
948
  }
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();
949
+ if (this.#recaptchaTokens) {
950
+ this.onConfirm?.(this.#recaptchaTokens);
951
+ this.close();
952
+ }
408
953
  });
409
954
  this.querySelector("#apple-pay-modal-close")?.addEventListener(
410
955
  "click",
411
956
  () => this.close()
412
957
  );
413
958
  }
414
- open() {
959
+ open(recaptchaTokensPromise) {
960
+ this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
415
961
  this.#triggerElement = document.activeElement;
416
962
  document.body.appendChild(this);
417
963
  this.#keyHandler = (event) => {
@@ -524,10 +1070,6 @@ var apple_pay_button_template_default = `<style>
524
1070
  </div>
525
1071
  `;
526
1072
 
527
- // src/clients/payment-checkout/config.ts
528
- var runtimeConfig = null;
529
- var getApplePayConfig = () => runtimeConfig;
530
-
531
1073
  // src/clients/payment-checkout/detects.ts
532
1074
  var isAppleDeviceOrSafari = () => {
533
1075
  const isIOSOrMacTouchDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent);
@@ -560,7 +1102,8 @@ var isApplePayAvailable = async () => {
560
1102
  );
561
1103
  return false;
562
1104
  }
563
- return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1105
+ const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1106
+ return hasActiveCard;
564
1107
  } catch (error) {
565
1108
  console.error("Error checking Apple Pay active card status:", error);
566
1109
  return false;
@@ -689,53 +1232,6 @@ var redirectToCheckoutFallback = (params) => {
689
1232
  return url.pathname + url.search;
690
1233
  };
691
1234
 
692
- // src/utils/recaptcha.ts
693
- var loadRecaptchaScript = (siteKey) => {
694
- return new Promise((resolve, reject) => {
695
- if (typeof grecaptcha !== "undefined") return resolve();
696
- const existingScript = document.querySelector(
697
- 'script[src*="recaptcha/api.js"]'
698
- );
699
- if (existingScript) {
700
- existingScript.addEventListener("load", () => resolve());
701
- existingScript.addEventListener(
702
- "error",
703
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
704
- );
705
- return;
706
- }
707
- const script = document.createElement("script");
708
- script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
709
- script.async = true;
710
- script.defer = true;
711
- script.onload = () => resolve();
712
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
713
- document.head.appendChild(script);
714
- });
715
- };
716
- var getRecaptchaToken = async (action) => {
717
- const siteKey = getApplePayConfig()?.recaptchaSiteKey;
718
- if (!siteKey) {
719
- throw new Error(
720
- "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
721
- );
722
- }
723
- await loadRecaptchaScript(siteKey);
724
- return new Promise((resolve, reject) => {
725
- grecaptcha.ready(() => {
726
- grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
727
- });
728
- });
729
- };
730
- var getPurchaseRecaptchaTokens = async () => {
731
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
732
- getRecaptchaToken("checkEligibility"),
733
- getRecaptchaToken("newBasket"),
734
- getRecaptchaToken("registerUser")
735
- ]);
736
- return { checkEligibility, newBasket, registerUser };
737
- };
738
-
739
1235
  // src/utils/expressCheckoutTracking.ts
740
1236
  var EXPRESS_CHECKOUT_EVENTS = {
741
1237
  /** Wallet button displayed */
@@ -848,7 +1344,8 @@ async function handleMerchantValidation(event, session, config) {
848
1344
  return;
849
1345
  }
850
1346
  session.completeMerchantValidation(response.merchantSession);
851
- } catch {
1347
+ } catch (err) {
1348
+ console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
852
1349
  session.abort();
853
1350
  redirectToFallbackCheckout(config);
854
1351
  }
@@ -881,7 +1378,8 @@ function startApplePaySession(config) {
881
1378
  };
882
1379
  trackWalletPaymentSheetOpen(config.skuId);
883
1380
  session.begin();
884
- } catch {
1381
+ } catch (err) {
1382
+ console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
885
1383
  redirectToFallbackCheckout(config);
886
1384
  }
887
1385
  }
@@ -1069,6 +1567,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1069
1567
  const result = await performPurchase({
1070
1568
  applePayToken: event.payment.token,
1071
1569
  skuId: config.skuId,
1570
+ currency: config.currency,
1072
1571
  billingContact: event.payment.billingContact,
1073
1572
  ...event.payment.shippingContact && {
1074
1573
  shippingContact: event.payment.shippingContact
@@ -1419,7 +1918,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1419
1918
  #returnUrl = "";
1420
1919
  #supportedBillingCountries = [];
1421
1920
  #entryPoint = "";
1422
- #recaptchaTokens = null;
1921
+ #recaptchaTokensPromise = null;
1423
1922
  // ─── Public API ─────────────────────────────────────────────────────────────
1424
1923
  get offer() {
1425
1924
  return this.#offer;
@@ -1484,6 +1983,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1484
1983
  this.#paymentOptions = null;
1485
1984
  this.#returnUrl = "";
1486
1985
  this.#supportedBillingCountries = [];
1986
+ this.#recaptchaTokensPromise = null;
1487
1987
  this.querySelector(SEL_CONTAINER)?.remove();
1488
1988
  }
1489
1989
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -1497,7 +1997,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1497
1997
  this.#computeBillingCountries();
1498
1998
  if (await this.#fetchAndCacheOptions()) return;
1499
1999
  this.#finishLoading();
1500
- } catch {
2000
+ } catch (err) {
2001
+ console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
1501
2002
  this.style.display = "none";
1502
2003
  this.querySelector(SEL_CONTAINER)?.remove();
1503
2004
  } finally {
@@ -1578,16 +2079,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1578
2079
  if (button.classList.contains("wap-loading")) return;
1579
2080
  this.#openModal();
1580
2081
  });
1581
- document.addEventListener("apple-pay-confirmed", (event) => {
1582
- const { skuId, country } = event.detail;
1583
- this.#initiateApplePay(skuId, country);
1584
- }, { once: true });
1585
2082
  }
1586
2083
  #finishLoading() {
1587
2084
  const button = this.querySelector(SEL_BUTTON);
1588
2085
  if (button) {
1589
2086
  button.classList.remove("wap-loading");
1590
2087
  this.#updateDisabledState();
2088
+ this.#scheduleRecaptchaTokens();
1591
2089
  trackExpressWalletImpression(this.#offer.sku_id, {
1592
2090
  entryPoint: this.#entryPoint,
1593
2091
  country: this.#country
@@ -1615,10 +2113,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1615
2113
  return;
1616
2114
  }
1617
2115
  trackExpressWalletClick(this.#offer.sku_id);
1618
- getPurchaseRecaptchaTokens().then((tokens) => {
1619
- this.#recaptchaTokens = tokens;
1620
- }).catch(() => {
1621
- });
1622
2116
  ApplePayModal.define();
1623
2117
  const modal = document.createElement(ApplePayModal.tag);
1624
2118
  modal.offer = this.#offer;
@@ -1626,7 +2120,30 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1626
2120
  if (this.#sessionData?.loggedIn) {
1627
2121
  modal.dataset.loggedIn = "true";
1628
2122
  }
1629
- modal.open();
2123
+ const skuId = this.#offer.sku_id;
2124
+ const country = this.#country;
2125
+ modal.onConfirm = (recaptchaTokens) => {
2126
+ this.#initiateApplePay(skuId, country, recaptchaTokens);
2127
+ this.#scheduleRecaptchaTokens();
2128
+ };
2129
+ modal.open(this.#recaptchaTokensPromise);
2130
+ }
2131
+ /**
2132
+ * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2133
+ * If the fetch rejects, the field is cleared so the next `modal.open()` call
2134
+ * falls back to a new attempt via the modal's own null-fallback path — preventing
2135
+ * a single transient failure from permanently disabling the CTA on all retries.
2136
+ * The identity guard prevents a late rejection from clobbering a newer attempt.
2137
+ */
2138
+ #scheduleRecaptchaTokens() {
2139
+ const attempt = getPurchaseRecaptchaTokens();
2140
+ attempt.catch((err) => {
2141
+ console.error("[web-apple-pay] reCAPTCHA token pre-fetch failed; will retry on modal open", err);
2142
+ if (this.#recaptchaTokensPromise === attempt) {
2143
+ this.#recaptchaTokensPromise = null;
2144
+ }
2145
+ });
2146
+ this.#recaptchaTokensPromise = attempt;
1630
2147
  }
1631
2148
  async #fetchSession() {
1632
2149
  try {
@@ -1662,6 +2179,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1662
2179
  onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
1663
2180
  skuId,
1664
2181
  country,
2182
+ currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1665
2183
  returnUrl: this.#returnUrl,
1666
2184
  queryString: buildQueryString(),
1667
2185
  supportedBillingCountries: this.#supportedBillingCountries,
@@ -1669,11 +2187,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1669
2187
  })
1670
2188
  };
1671
2189
  }
1672
- async #initiateApplePay(skuId, country) {
2190
+ #initiateApplePay(skuId, country, recaptchaTokens) {
1673
2191
  try {
1674
2192
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1675
2193
  const paymentOptions = this.#paymentOptions;
1676
- const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1677
2194
  startApplePaySession(
1678
2195
  this.#buildSessionParams(
1679
2196
  skuId,