@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,517 @@ 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
+ var resetApplePayConfig = () => {
541
+ runtimeConfig = null;
542
+ };
543
+
544
+ // src/utils/recaptcha.ts
545
+ var loadRecaptchaScript = (siteKey) => {
546
+ return new Promise((resolve, reject) => {
547
+ if (typeof grecaptcha !== "undefined") return resolve();
548
+ const existingScript = document.querySelector(
549
+ 'script[src*="recaptcha/api.js"]'
550
+ );
551
+ if (existingScript) {
552
+ existingScript.addEventListener("load", () => resolve());
553
+ existingScript.addEventListener(
554
+ "error",
555
+ () => reject(new Error("Failed to load existing reCAPTCHA script"))
556
+ );
557
+ return;
558
+ }
559
+ const script = document.createElement("script");
560
+ script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
561
+ script.async = true;
562
+ script.defer = true;
563
+ script.onload = () => resolve();
564
+ script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
565
+ document.head.appendChild(script);
566
+ });
567
+ };
568
+ var getRecaptchaToken = async (action) => {
569
+ const siteKey = getApplePayConfig()?.recaptchaSiteKey;
570
+ if (!siteKey) {
571
+ throw new Error(
572
+ "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
573
+ );
574
+ }
575
+ await loadRecaptchaScript(siteKey);
576
+ return new Promise((resolve, reject) => {
577
+ grecaptcha.ready(() => {
578
+ grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
579
+ });
580
+ });
581
+ };
582
+ var getPurchaseRecaptchaTokens = async () => {
583
+ const [checkEligibility, newBasket, registerUser] = await Promise.all([
584
+ getRecaptchaToken("checkEligibility"),
585
+ getRecaptchaToken("newBasket"),
586
+ getRecaptchaToken("registerUser")
587
+ ]);
588
+ return { checkEligibility, newBasket, registerUser };
589
+ };
80
590
 
81
591
  // src/apple-pay-modal.ts
82
592
  function getRenewalDateText(unit, duration) {
@@ -128,6 +638,7 @@ function getOfferTypeText(offerType) {
128
638
  }
129
639
  var TERMS_LINK = '<a href="https://www.economistgroup.com/terms-of-use" target="_blank" rel="noopener noreferrer">Terms and Conditions</a>';
130
640
  var PRIVACY_LINK = '<a href="https://www.economistgroup.com/privacy-policy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>';
641
+ var MSG_RECAPTCHA_LOAD_ERROR = "Something went wrong. Please close and try again.";
131
642
  function getCheckboxTermsHtml(isNYT, isLoggedIn, autoRenewal) {
132
643
  const autoRenewalClause = autoRenewal ? " and auto-renewal terms above," : "";
133
644
  if (isNYT) {
@@ -297,6 +808,19 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
297
808
  #country = "";
298
809
  #triggerElement = null;
299
810
  #keyHandler = null;
811
+ #recaptchaTokens = null;
812
+ #recaptchaTokensPromise = null;
813
+ /**
814
+ * Synchronous callback invoked directly from the CTA click handler once the
815
+ * user confirms. The caller (ApplePayButton) must call startApplePaySession
816
+ * inside this callback to preserve the browser's user-gesture chain — Safari
817
+ * requires new ApplePaySession() to execute within the original click stack.
818
+ *
819
+ * reCAPTCHA tokens are guaranteed non-null here: the CTA remains disabled
820
+ * until the token pre-fetch resolves, so this callback is never reached
821
+ * without valid tokens.
822
+ */
823
+ onConfirm = null;
300
824
  set offer(value) {
301
825
  this.#offer = value;
302
826
  }
@@ -391,27 +915,57 @@ var ApplePayModal = class _ApplePayModal extends HTMLElement {
391
915
  }
392
916
  });
393
917
  }
918
+ if (this.#recaptchaTokensPromise) {
919
+ if (cta) {
920
+ cta.setAttribute("disabled", "");
921
+ cta.setAttribute("aria-disabled", "true");
922
+ cta.setAttribute("aria-busy", "true");
923
+ }
924
+ this.#recaptchaTokensPromise.then((tokens) => {
925
+ this.#recaptchaTokens = tokens;
926
+ if (cta) {
927
+ cta.removeAttribute("disabled");
928
+ cta.removeAttribute("aria-disabled");
929
+ cta.removeAttribute("aria-busy");
930
+ }
931
+ }).catch(() => {
932
+ console.error("[web-apple-pay] apple-pay-modal: failed to pre-fetch reCAPTCHA tokens; CTA remains disabled");
933
+ if (cta) {
934
+ cta.removeAttribute("aria-busy");
935
+ }
936
+ const existingError = this.querySelector("#apple-pay-modal-error");
937
+ if (existingError) {
938
+ const icon = existingError.querySelector("svg");
939
+ existingError.textContent = MSG_RECAPTCHA_LOAD_ERROR;
940
+ if (icon) existingError.prepend(icon);
941
+ existingError.classList.add("apm__error--visible");
942
+ } else {
943
+ const errorNotice = document.createElement("div");
944
+ errorNotice.setAttribute("role", "alert");
945
+ errorNotice.className = "apm__error apm__error--visible";
946
+ errorNotice.textContent = MSG_RECAPTCHA_LOAD_ERROR;
947
+ cta?.insertAdjacentElement("beforebegin", errorNotice);
948
+ }
949
+ });
950
+ }
394
951
  cta?.addEventListener("click", () => {
395
952
  if (isUS && checkbox && !checkbox.checked) {
396
953
  errorElement?.classList.add("apm__error--visible");
397
954
  checkboxLabel?.classList.add("apm__checkbox-label--error");
398
955
  return;
399
956
  }
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();
957
+ if (this.#recaptchaTokens) {
958
+ this.onConfirm?.(this.#recaptchaTokens);
959
+ this.close();
960
+ }
408
961
  });
409
962
  this.querySelector("#apple-pay-modal-close")?.addEventListener(
410
963
  "click",
411
964
  () => this.close()
412
965
  );
413
966
  }
414
- open() {
967
+ open(recaptchaTokensPromise) {
968
+ this.#recaptchaTokensPromise = recaptchaTokensPromise ?? getPurchaseRecaptchaTokens();
415
969
  this.#triggerElement = document.activeElement;
416
970
  document.body.appendChild(this);
417
971
  this.#keyHandler = (event) => {
@@ -524,18 +1078,6 @@ var apple_pay_button_template_default = `<style>
524
1078
  </div>
525
1079
  `;
526
1080
 
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
- var resetApplePayConfig = () => {
536
- runtimeConfig = null;
537
- };
538
-
539
1081
  // src/clients/payment-checkout/detects.ts
540
1082
  var isAppleDeviceOrSafari = () => {
541
1083
  const isIOSOrMacTouchDevice = /iPad|iPhone|iPod/.test(navigator.userAgent) || navigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent);
@@ -568,7 +1110,8 @@ var isApplePayAvailable = async () => {
568
1110
  );
569
1111
  return false;
570
1112
  }
571
- return await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1113
+ const hasActiveCard = await applePaySession.canMakePaymentsWithActiveCard(merchantId);
1114
+ return hasActiveCard;
572
1115
  } catch (error) {
573
1116
  console.error("Error checking Apple Pay active card status:", error);
574
1117
  return false;
@@ -697,53 +1240,6 @@ var redirectToCheckoutFallback = (params) => {
697
1240
  return url.pathname + url.search;
698
1241
  };
699
1242
 
700
- // src/utils/recaptcha.ts
701
- var loadRecaptchaScript = (siteKey) => {
702
- return new Promise((resolve, reject) => {
703
- if (typeof grecaptcha !== "undefined") return resolve();
704
- const existingScript = document.querySelector(
705
- 'script[src*="recaptcha/api.js"]'
706
- );
707
- if (existingScript) {
708
- existingScript.addEventListener("load", () => resolve());
709
- existingScript.addEventListener(
710
- "error",
711
- () => reject(new Error("Failed to load existing reCAPTCHA script"))
712
- );
713
- return;
714
- }
715
- const script = document.createElement("script");
716
- script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}`;
717
- script.async = true;
718
- script.defer = true;
719
- script.onload = () => resolve();
720
- script.onerror = () => reject(new Error("Failed to load reCAPTCHA script"));
721
- document.head.appendChild(script);
722
- });
723
- };
724
- var getRecaptchaToken = async (action) => {
725
- const siteKey = getApplePayConfig()?.recaptchaSiteKey;
726
- if (!siteKey) {
727
- throw new Error(
728
- "[web-apple-pay] Missing recaptchaSiteKey. Call configureApplePay({ recaptchaSiteKey, ... }) before initiating Apple Pay."
729
- );
730
- }
731
- await loadRecaptchaScript(siteKey);
732
- return new Promise((resolve, reject) => {
733
- grecaptcha.ready(() => {
734
- grecaptcha.execute(siteKey, { action }).then(resolve).catch(reject);
735
- });
736
- });
737
- };
738
- var getPurchaseRecaptchaTokens = async () => {
739
- const [checkEligibility, newBasket, registerUser] = await Promise.all([
740
- getRecaptchaToken("checkEligibility"),
741
- getRecaptchaToken("newBasket"),
742
- getRecaptchaToken("registerUser")
743
- ]);
744
- return { checkEligibility, newBasket, registerUser };
745
- };
746
-
747
1243
  // src/utils/expressCheckoutTracking.ts
748
1244
  var EXPRESS_CHECKOUT_EVENTS = {
749
1245
  /** Wallet button displayed */
@@ -856,7 +1352,8 @@ async function handleMerchantValidation(event, session, config) {
856
1352
  return;
857
1353
  }
858
1354
  session.completeMerchantValidation(response.merchantSession);
859
- } catch {
1355
+ } catch (err) {
1356
+ console.error("[web-apple-pay] onvalidatemerchant: error during validation", err);
860
1357
  session.abort();
861
1358
  redirectToFallbackCheckout(config);
862
1359
  }
@@ -889,7 +1386,8 @@ function startApplePaySession(config) {
889
1386
  };
890
1387
  trackWalletPaymentSheetOpen(config.skuId);
891
1388
  session.begin();
892
- } catch {
1389
+ } catch (err) {
1390
+ console.error("[web-apple-pay] startApplePaySession: failed to create session", err);
893
1391
  redirectToFallbackCheckout(config);
894
1392
  }
895
1393
  }
@@ -1077,6 +1575,7 @@ async function handlePaymentAuthorized(event, session, sessionData, config) {
1077
1575
  const result = await performPurchase({
1078
1576
  applePayToken: event.payment.token,
1079
1577
  skuId: config.skuId,
1578
+ currency: config.currency,
1080
1579
  billingContact: event.payment.billingContact,
1081
1580
  ...event.payment.shippingContact && {
1082
1581
  shippingContact: event.payment.shippingContact
@@ -1427,7 +1926,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1427
1926
  #returnUrl = "";
1428
1927
  #supportedBillingCountries = [];
1429
1928
  #entryPoint = "";
1430
- #recaptchaTokens = null;
1929
+ #recaptchaTokensPromise = null;
1431
1930
  // ─── Public API ─────────────────────────────────────────────────────────────
1432
1931
  get offer() {
1433
1932
  return this.#offer;
@@ -1492,6 +1991,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1492
1991
  this.#paymentOptions = null;
1493
1992
  this.#returnUrl = "";
1494
1993
  this.#supportedBillingCountries = [];
1994
+ this.#recaptchaTokensPromise = null;
1495
1995
  this.querySelector(SEL_CONTAINER)?.remove();
1496
1996
  }
1497
1997
  // ─── Render pipeline ────────────────────────────────────────────────────────
@@ -1505,7 +2005,8 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1505
2005
  this.#computeBillingCountries();
1506
2006
  if (await this.#fetchAndCacheOptions()) return;
1507
2007
  this.#finishLoading();
1508
- } catch {
2008
+ } catch (err) {
2009
+ console.error("[web-apple-pay] #run: unexpected error, hiding button", err);
1509
2010
  this.style.display = "none";
1510
2011
  this.querySelector(SEL_CONTAINER)?.remove();
1511
2012
  } finally {
@@ -1586,16 +2087,13 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1586
2087
  if (button.classList.contains("wap-loading")) return;
1587
2088
  this.#openModal();
1588
2089
  });
1589
- document.addEventListener("apple-pay-confirmed", (event) => {
1590
- const { skuId, country } = event.detail;
1591
- this.#initiateApplePay(skuId, country);
1592
- }, { once: true });
1593
2090
  }
1594
2091
  #finishLoading() {
1595
2092
  const button = this.querySelector(SEL_BUTTON);
1596
2093
  if (button) {
1597
2094
  button.classList.remove("wap-loading");
1598
2095
  this.#updateDisabledState();
2096
+ this.#scheduleRecaptchaTokens();
1599
2097
  trackExpressWalletImpression(this.#offer.sku_id, {
1600
2098
  entryPoint: this.#entryPoint,
1601
2099
  country: this.#country
@@ -1623,10 +2121,6 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1623
2121
  return;
1624
2122
  }
1625
2123
  trackExpressWalletClick(this.#offer.sku_id);
1626
- getPurchaseRecaptchaTokens().then((tokens) => {
1627
- this.#recaptchaTokens = tokens;
1628
- }).catch(() => {
1629
- });
1630
2124
  ApplePayModal.define();
1631
2125
  const modal = document.createElement(ApplePayModal.tag);
1632
2126
  modal.offer = this.#offer;
@@ -1634,7 +2128,30 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1634
2128
  if (this.#sessionData?.loggedIn) {
1635
2129
  modal.dataset.loggedIn = "true";
1636
2130
  }
1637
- modal.open();
2131
+ const skuId = this.#offer.sku_id;
2132
+ const country = this.#country;
2133
+ modal.onConfirm = (recaptchaTokens) => {
2134
+ this.#initiateApplePay(skuId, country, recaptchaTokens);
2135
+ this.#scheduleRecaptchaTokens();
2136
+ };
2137
+ modal.open(this.#recaptchaTokensPromise);
2138
+ }
2139
+ /**
2140
+ * Starts a fresh reCAPTCHA token pre-fetch and stores its promise.
2141
+ * If the fetch rejects, the field is cleared so the next `modal.open()` call
2142
+ * falls back to a new attempt via the modal's own null-fallback path — preventing
2143
+ * a single transient failure from permanently disabling the CTA on all retries.
2144
+ * The identity guard prevents a late rejection from clobbering a newer attempt.
2145
+ */
2146
+ #scheduleRecaptchaTokens() {
2147
+ const attempt = getPurchaseRecaptchaTokens();
2148
+ attempt.catch((err) => {
2149
+ console.error("[web-apple-pay] reCAPTCHA token pre-fetch failed; will retry on modal open", err);
2150
+ if (this.#recaptchaTokensPromise === attempt) {
2151
+ this.#recaptchaTokensPromise = null;
2152
+ }
2153
+ });
2154
+ this.#recaptchaTokensPromise = attempt;
1638
2155
  }
1639
2156
  async #fetchSession() {
1640
2157
  try {
@@ -1670,6 +2187,7 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1670
2187
  onPaymentAuthorized: (event, session) => handlePaymentAuthorized(event, session, sessionData, {
1671
2188
  skuId,
1672
2189
  country,
2190
+ currency: offer.price?.currency_code ?? DEFAULT_CURRENCY,
1673
2191
  returnUrl: this.#returnUrl,
1674
2192
  queryString: buildQueryString(),
1675
2193
  supportedBillingCountries: this.#supportedBillingCountries,
@@ -1677,11 +2195,10 @@ var ApplePayButton = class _ApplePayButton extends HTMLElement {
1677
2195
  })
1678
2196
  };
1679
2197
  }
1680
- async #initiateApplePay(skuId, country) {
2198
+ #initiateApplePay(skuId, country, recaptchaTokens) {
1681
2199
  try {
1682
2200
  const sessionData = this.#sessionData ?? _ApplePayButton.#ANONYMOUS_SESSION;
1683
2201
  const paymentOptions = this.#paymentOptions;
1684
- const recaptchaTokens = this.#recaptchaTokens ?? await getPurchaseRecaptchaTokens();
1685
2202
  startApplePaySession(
1686
2203
  this.#buildSessionParams(
1687
2204
  skuId,
@@ -1752,6 +2269,24 @@ var createFetchMock = (sessionResponse, sessionStatus = 200) => {
1752
2269
  headers: { "content-type": "application/json" }
1753
2270
  });
1754
2271
  }
2272
+ if (requestUrl.includes("/v1/wallet/payment-options/sku/")) {
2273
+ return new Response(
2274
+ JSON.stringify({
2275
+ options: {
2276
+ apple_pay: {
2277
+ provider: "apple-pay",
2278
+ settings: {
2279
+ supported_networks: ["visa", "masterCard", "amex"]
2280
+ }
2281
+ }
2282
+ }
2283
+ }),
2284
+ {
2285
+ status: 200,
2286
+ headers: { "content-type": "application/json" }
2287
+ }
2288
+ );
2289
+ }
1755
2290
  return new Response("Not Found", {
1756
2291
  status: 404,
1757
2292
  statusText: "Not Found"