smartphoto 2.1.3 → 2.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -70,6 +70,14 @@ document.addEventListener('DOMContentLoaded',function(){
70
70
  </script>
71
71
  ```
72
72
 
73
+ When SmartPhoto is constructed with a CSS selector string (as above), clicks are handled via a single delegated listener, so elements added to the page **after** construction (e.g. by Ajax/infinite scroll) are picked up automatically just by clicking them — no need to call `addItem()`/`addNewItem()` manually. Right before a photo is opened, SmartPhoto also reconciles that photo's group against the current DOM: newly appended matching elements are added, and elements that have since been removed from the DOM are dropped from the group (remaining indices are recalculated). This auto-detection only applies to the selector-string form; when a `NodeList`/`Element[]` is passed (or in data source mode below), add/remove items explicitly via `addItem()`/`addNewItem()`.
74
+
75
+ A few things to keep in mind:
76
+ - Reconciliation only happens **right before a photo is opened** (via a click, `show()`, or hash restoration) — not continuously. If an element disappears from the DOM while the viewer is already open and you `next()`/`prev()` through the same session, that removal isn't reflected until the viewer is opened again.
77
+ - It does not support replacing an entire container's `innerHTML` (which recreates existing elements too, as brand-new DOM nodes) — that produces duplicate items, since the old and new elements aren't recognized as the same one. Only *appending*/*removing* individual elements is supported; if you regenerate the whole container, call `destroy()` and construct a new instance instead.
78
+ - Changing `data-group` on an element that has already been opened/registered has no effect (the group is fixed at first registration). Changing it before the element is first interacted with is picked up correctly.
79
+ - If multiple instances are built with overlapping selectors, avoid relying on distinguishing exactly which instance handles a click for elements that could match either.
80
+
73
81
  ### Programmatic usage (data source mode)
74
82
 
75
83
  Instead of scanning `<a>` elements in the page, you can pass an array of slide objects directly (inspired by [yet-another-react-lightbox](https://yet-another-react-lightbox.com/)). This is useful when your images come from an API or a JS-rendered list.
@@ -188,6 +196,11 @@ Slide fields:
188
196
  <td>minimum swipe distance (px) to trigger navigation/close</td>
189
197
  <td>100</td>
190
198
  </tr>
199
+ <tr>
200
+ <td>swipeVelocity</td>
201
+ <td>minimum swipe speed (px/ms) that triggers navigation even below swipeOffset (fast flicks)</td>
202
+ <td>0.5</td>
203
+ </tr>
191
204
  <tr>
192
205
  <td>headerHeight</td>
193
206
  <td>height (px) reserved for the header when fitting images</td>
@@ -206,7 +219,7 @@ Slide fields:
206
219
  <tr>
207
220
  <td>animationSpeed</td>
208
221
  <td>animation speed (ms) when switching/opening/closing images</td>
209
- <td>300</td>
222
+ <td>450</td>
210
223
  </tr>
211
224
  <tr>
212
225
  <td>forceInterval</td>
@@ -332,7 +345,7 @@ photo.on('zoomout',function(){
332
345
  </tr>
333
346
  <tr>
334
347
  <td><code>addNewItem(element)</code></td>
335
- <td>register a new <code>&lt;a&gt;</code> thumbnail element (HTML mode)</td>
348
+ <td>register a new <code>&lt;a&gt;</code> thumbnail element (HTML mode). Only needed when constructed with a <code>NodeList</code>/<code>Element[]</code> or otherwise not using a selector string — with a selector string, elements added later are auto-detected on click (see above)</td>
336
349
  </tr>
337
350
  <tr>
338
351
  <td><code>show(indexOrId?, options?)</code></td>
@@ -348,7 +361,7 @@ photo.on('zoomout',function(){
348
361
  </tr>
349
362
  <tr>
350
363
  <td><code>addItem(slideOrElement)</code></td>
351
- <td>add a new item. Accepts a slide object (data source mode) or an <code>Element</code> (HTML mode, same as <code>addNewItem</code>)</td>
364
+ <td>add a new item. Accepts a slide object (data source mode, where explicit registration is always required) or an <code>Element</code> (HTML mode, same caveat as <code>addNewItem</code>)</td>
352
365
  </tr>
353
366
  <tr>
354
367
  <td><code>currentIndex</code></td>
@@ -367,7 +380,7 @@ photo.on('zoomout',function(){
367
380
  <tr>
368
381
  <td>--smartphoto-animation-speed</td>
369
382
  <td>animation speed when switching/opening/closing images. Overridden per-instance by the <code>animationSpeed</code> JS option</td>
370
- <td>300ms</td>
383
+ <td>450ms</td>
371
384
  </tr>
372
385
  <tr>
373
386
  <td>--smartphoto-animation-function</td>
@@ -390,7 +403,7 @@ Set these on `.smartphoto` (or `:root`) to override the defaults, no rebuild req
390
403
 
391
404
  ```css
392
405
  .smartphoto {
393
- --smartphoto-animation-speed: 500ms;
406
+ --smartphoto-animation-speed: 450ms;
394
407
  --smartphoto-animation-function: ease-in-out;
395
408
  --smartphoto-backdrop-color: rgba(0, 0, 0, 0.9);
396
409
  --smartphoto-header-color: rgba(0, 0, 0, 0.4);
@@ -2,26 +2,32 @@
2
2
  from {
3
3
  opacity: 0;
4
4
  }
5
+
5
6
  to {
6
7
  opacity: 1;
7
8
  }
8
9
  }
10
+
9
11
  @keyframes smartphoto-img-wrap {
10
12
  from {
11
13
  opacity: 0;
12
14
  }
15
+
13
16
  to {
14
17
  opacity: 1;
15
18
  }
16
19
  }
20
+
17
21
  @keyframes smartphoto-inner {
18
22
  from {
19
23
  transform: translate(0, 100px);
20
24
  }
25
+
21
26
  to {
22
27
  transform: translate(0, 0);
23
28
  }
24
29
  }
30
+
25
31
  @keyframes smartphoto-loader {
26
32
  0% {
27
33
  opacity: 0.4;
@@ -36,14 +42,23 @@
36
42
  transform: rotate(360deg);
37
43
  }
38
44
  }
45
+
46
+ /* display の切り替えをキーフレーム内でアニメーションさせていた版は、閉じている間
47
+ * (dialog が display:none)にアニメーションのタイムラインが進まなくなり、再度開いた
48
+ * 際に 0%/1% の display:none で止まったままになる実機バグがあった(矢印/ナビが
49
+ * クリック不能になり、その下の背景をタップしたと判定されてモーダルが閉じてしまう)。
50
+ * 表示/非表示そのものは常に aria-hidden 属性のセレクタ側(下記)で確定させ、
51
+ * ここでは opacity のフェードのみをアニメーションする */
39
52
  @keyframes smartphoto-appear {
40
53
  0% {
41
54
  opacity: 0;
42
55
  }
56
+
43
57
  100% {
44
58
  opacity: 1;
45
59
  }
46
60
  }
61
+
47
62
  @keyframes smartphoto-hide {
48
63
  0% {
49
64
  opacity: 1;
@@ -52,42 +67,71 @@
52
67
  opacity: 0;
53
68
  }
54
69
  }
70
+
55
71
  :root:has(dialog.smartphoto[open]) {
56
72
  overflow: hidden;
57
73
  }
58
74
 
75
+ /* dialogタグの表示制御 */
59
76
  .smartphoto {
77
+ /* dialogタグのデフォルトスタイルをリセット */
60
78
  border: none;
61
79
  background: transparent;
62
80
  padding: 0;
63
81
  margin: 0;
64
82
  outline: none;
83
+ /* 既存のスタイルを適用 */
65
84
  position: fixed;
66
85
  inset: 0;
67
86
  width: 100%;
68
87
  height: 100%;
69
88
  max-width: 100%;
70
89
  max-height: 100%;
90
+ /* dialog 自体には overflow の既定値が無く、子要素(nav/arrows 等)が僅かに
91
+ * ボックスを超えるだけで dialog 自身がスクロール可能になってしまう。
92
+ * 内側のスクロールは常に禁止し、外側の背景スクロール抑制(:root:has())と
93
+ * 合わせて完全に固定表示にする */
71
94
  overflow: hidden;
95
+ /* モバイルでスクロールに伴いアドレスバーが表示/非表示になり可視領域が変化しても
96
+ * 追従するよう、dvh (動的ビューポート高さ) を優先する
97
+ * (see: https://github.com/appleple/SmartPhoto/issues/90)。
98
+ * dvh はブラウザによってはアドレスバーの伸縮への追従が実装依存で不安定なため、
99
+ * JS で実測して設定する --smartphoto-vh (updateViewportHeight() 参照) があれば
100
+ * それを優先し、JS 無効時やブラウザ未対応時は height:100%/max-height:100% に
101
+ * フォールバックする */
72
102
  height: var(--smartphoto-vh, 100dvh);
73
103
  max-height: var(--smartphoto-vh, 100dvh);
74
- background-color: var(--smartphoto-backdrop-color, rgb(0, 0, 0));
104
+ background-color: var(--smartphoto-backdrop-color, rgba(0, 0, 0, 1));
75
105
  opacity: 1;
76
106
  font-family: sans-serif;
77
107
  cursor: pointer;
78
- transition: opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out), display var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out) allow-discrete, overlay var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out) allow-discrete;
108
+ /* close() [open] 属性を外すと同時にネイティブに display:none / トップレイヤー
109
+ * からの除外を行う(§8)。display・overlay を allow-discrete で transition
110
+ * 対象に加えることで、opacity のフェードが完了するまでその適用を1フレーム分
111
+ * 遅らせ、閉じる瞬間に「ぱっと」消えず滑らかにフェードアウトするようにする */
112
+ transition:
113
+ opacity var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out),
114
+ display var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out) allow-discrete,
115
+ overlay var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out) allow-discrete;
79
116
  }
117
+
80
118
  .smartphoto:not([open]) {
81
119
  opacity: 0;
82
120
  }
121
+
83
122
  .smartphoto::backdrop {
84
- background-color: var(--smartphoto-backdrop-color, rgb(0, 0, 0));
123
+ background-color: var(--smartphoto-backdrop-color, rgba(0, 0, 0, 1));
85
124
  }
86
125
 
126
+ /* View Transition(openPhotoWithViewTransition() 参照)の疑似要素ツリーは document の
127
+ * ルート要素(html)の子として扱われ、dialog に設定した --smartphoto-animation-speed を
128
+ * 継承しない。そのため JS 側では document.documentElement にも同じ変数を設定しており、
129
+ * ここではその値を参照する。指定がなければブラウザ既定(実装依存, 概ね0.25s前後で
130
+ * 速すぎるとの声があった)の代わりに 0.45s を使う */
87
131
  ::view-transition-group(smartphoto-hero),
88
132
  ::view-transition-old(smartphoto-hero),
89
133
  ::view-transition-new(smartphoto-hero) {
90
- animation-duration: var(--smartphoto-animation-speed, 0.3s);
134
+ animation-duration: var(--smartphoto-animation-speed, 0.45s);
91
135
  animation-timing-function: var(--smartphoto-animation-function, ease-out);
92
136
  }
93
137
 
@@ -121,6 +165,7 @@
121
165
  left: 0;
122
166
  width: 100%;
123
167
  height: 100%;
168
+ /* Pointer Events(swipe/pinch)がブラウザ既定のスクロール・ズームと衝突しないようにする */
124
169
  touch-action: none;
125
170
  }
126
171
 
@@ -168,7 +213,8 @@
168
213
  -moz-user-select: none;
169
214
  -ms-user-select: none;
170
215
  user-select: none;
171
- transition: transform var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
216
+ transition: transform var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
217
+
172
218
  -webkit-user-drag: none;
173
219
  }
174
220
 
@@ -183,20 +229,21 @@
183
229
  }
184
230
 
185
231
  .smartphoto-img-elasticmove {
186
- transition: transform var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
232
+ transition: transform var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
187
233
  }
188
234
 
189
235
  .smartphoto-img-wrap {
190
236
  display: inline-block;
191
237
  opacity: 1;
238
+ /* Pointer Events(ピンチ/ドラッグ)がブラウザ既定のスクロール・ズームと衝突しないようにする */
192
239
  touch-action: none;
193
- -webkit-transition: opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
194
- -moz-transition: opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
195
- -ms-transition: opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
196
- -o-transition: opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
197
- transition: opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
240
+ -webkit-transition: opacity var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
241
+ -moz-transition: opacity var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
242
+ -ms-transition: opacity var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
243
+ -o-transition: opacity var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
244
+ transition: opacity var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
198
245
  animation-name: smartphoto-img-wrap;
199
- animation-duration: var(--smartphoto-animation-speed, 0.3s);
246
+ animation-duration: var(--smartphoto-animation-speed, 0.45s);
200
247
  animation-timing-function: var(--smartphoto-animation-function, ease-out);
201
248
  }
202
249
 
@@ -218,11 +265,11 @@
218
265
  left: 0;
219
266
  opacity: 1;
220
267
  animation-name: smartphoto-appear;
221
- animation-duration: var(--smartphoto-animation-speed, 0.3s);
268
+ animation-duration: var(--smartphoto-animation-speed, 0.45s);
222
269
  animation-timing-function: var(--smartphoto-animation-function, ease-out);
223
270
  }
224
271
 
225
- .smartphoto-arrows[aria-hidden=true] {
272
+ .smartphoto-arrows[aria-hidden='true'] {
226
273
  animation-name: smartphoto-hide;
227
274
  display: none;
228
275
  }
@@ -235,20 +282,23 @@
235
282
  height: 30px;
236
283
  margin-top: -20px;
237
284
  box-sizing: content-box;
238
- animation-duration: var(--smartphoto-animation-speed, 0.3s);
285
+ animation-duration: var(--smartphoto-animation-speed, 0.45s);
239
286
  animation-timing-function: var(--smartphoto-animation-function, ease-out);
240
287
  animation-name: smartphoto-appear;
241
288
  }
289
+
242
290
  .smartphoto-arrows li:focus {
243
291
  outline: none;
244
292
  }
245
293
 
246
- .smartphoto-arrows [aria-hidden=true] {
294
+ .smartphoto-arrows [aria-hidden='true'] {
247
295
  animation-name: smartphoto-hide;
248
296
  display: none;
249
297
  }
250
298
 
251
299
  .smartphoto-arrows button {
300
+ /* <button> の UA デフォルト(border/padding/背景/appearance)をリセットし、
301
+ * 旧 <a> と同じ「全面クリック領域 + 背景 SVG アイコン」の見た目を維持する */
252
302
  appearance: none;
253
303
  display: block;
254
304
  width: 100%;
@@ -265,6 +315,7 @@
265
315
  padding: 5px 0;
266
316
  background-color: rgba(0, 0, 0, 0.5);
267
317
  }
318
+
268
319
  .smartphoto-arrow-right button {
269
320
  background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0i44Os44Kk44Ok44O8XzEiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI4MzQuNjUgMjgzNC42NSIgZmlsbD0iI0ZGRiAiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTgzNy44OCwxNDE3LjMyLDY0My41OSwyMjNhNzIuMjEsNzIuMjEsMCwwLDEsMC0xMDEuODJMNzQzLjgyLDIxYTcyLjIxLDcyLjIxLDAsMCwxLDEwMS44MiwwTDIwOTAuODMsMTI2Ni4xOWwxMDAuMjMsMTAwLjIzYTcyLjIxLDcyLjIxLDAsMCwxLDAsMTAxLjgyTDg0NS42NCwyODEzLjY1YTcyLjIxLDcyLjIxLDAsMCwxLTEwMS44MiwwTDY0My41OSwyNzEzLjQyYTcyLjIxLDcyLjIxLDAsMCwxLDAtMTAxLjgyWiIvPjwvc3ZnPg==);
270
321
  }
@@ -274,6 +325,7 @@
274
325
  padding: 5px 0;
275
326
  background-color: rgba(0, 0, 0, 0.5);
276
327
  }
328
+
277
329
  .smartphoto-arrow-left button {
278
330
  background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0i44Os44Kk44Ok44O8XzEiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI4MzQuNjUgMjgzNC42NSIgZmlsbD0iI0ZGRiI+PHRpdGxlPmljb248L3RpdGxlPjxwYXRoIGQ9Ik05OTYuNzcsMTQxNy4zMiwyMTkxLjA2LDIyM2E3Mi4yMSw3Mi4yMSwwLDAsMCwwLTEwMS44MkwyMDkwLjgzLDIxQTcyLjIxLDcyLjIxLDAsMCwwLDE5ODksMjFMNzQzLjgyLDEyNjYuMTksNjQzLjU5LDEzNjYuNDJhNzIuMjEsNzIuMjEsMCwwLDAsMCwxMDEuODJMMTk4OSwyODEzLjY1YTcyLjIxLDcyLjIxLDAsMCwwLDEwMS44MiwwbDEwMC4yMy0xMDAuMjNhNzIuMjEsNzIuMjEsMCwwLDAsMC0xMDEuODJaIi8+PC9zdmc+);
279
331
  }
@@ -289,11 +341,11 @@
289
341
  width: 100%;
290
342
  opacity: 1;
291
343
  animation-name: smartphoto-appear;
292
- animation-duration: var(--smartphoto-animation-speed, 0.3s);
344
+ animation-duration: var(--smartphoto-animation-speed, 0.45s);
293
345
  animation-timing-function: var(--smartphoto-animation-function, ease-out);
294
346
  }
295
347
 
296
- .smartphoto-nav[aria-hidden=true] {
348
+ .smartphoto-nav[aria-hidden='true'] {
297
349
  animation-name: smartphoto-hide;
298
350
  display: none;
299
351
  }
@@ -306,6 +358,7 @@
306
358
  padding: 0;
307
359
  text-align: center;
308
360
  white-space: nowrap;
361
+
309
362
  -webkit-overflow-scrolling: touch;
310
363
  }
311
364
 
@@ -317,6 +370,8 @@
317
370
  }
318
371
 
319
372
  .smartphoto-nav button {
373
+ /* <button> の UA デフォルト(border/padding/appearance)をリセットし、
374
+ * 旧 <a> と同じサムネイル背景画像ボタンの見た目を維持する */
320
375
  appearance: none;
321
376
  display: block;
322
377
  width: 100%;
@@ -330,6 +385,7 @@
330
385
  opacity: 0.5;
331
386
  cursor: pointer;
332
387
  }
388
+
333
389
  .smartphoto-nav button:focus {
334
390
  opacity: 0.8;
335
391
  }
@@ -353,6 +409,7 @@
353
409
  padding: 0;
354
410
  white-space: nowrap;
355
411
  }
412
+
356
413
  .smartphoto-list li {
357
414
  display: block;
358
415
  position: absolute;
@@ -360,8 +417,9 @@
360
417
  left: 0;
361
418
  width: 100%;
362
419
  height: 100%;
363
- transition: all var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
420
+ transition: all var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
364
421
  }
422
+
365
423
  .smartphoto-list li:focus {
366
424
  outline: none;
367
425
  }
@@ -388,6 +446,7 @@
388
446
  margin: 0;
389
447
  font-weight: normal;
390
448
  }
449
+
391
450
  .smartphoto-caption:focus {
392
451
  outline: none;
393
452
  }
@@ -399,6 +458,9 @@
399
458
  width: 0;
400
459
  height: 0;
401
460
  transform: translate(50vw, 50vh);
461
+ /* dvh 対応ブラウザでは動的ビューポート高さを基準に中央寄せする
462
+ * (see: https://github.com/appleple/SmartPhoto/issues/90)。
463
+ * --smartphoto-vh (updateViewportHeight() 参照) が設定されていればそちらを優先する(§) */
402
464
  transform: translate(50vw, 50dvh);
403
465
  transform: translate(50vw, calc(var(--smartphoto-vh, 100dvh) / 2));
404
466
  }
@@ -423,7 +485,7 @@
423
485
  z-index: 100;
424
486
  top: 0;
425
487
  left: 0;
426
- transition: all var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);
488
+ transition: all var(--smartphoto-animation-speed, 0.45s) var(--smartphoto-animation-function, ease-out);
427
489
  }
428
490
 
429
491
  .smartphoto-sr-only {
@@ -436,5 +498,3 @@
436
498
  border: 0;
437
499
  clip: rect(0, 0, 0, 0);
438
500
  }
439
-
440
- /*# sourceMappingURL=smartphoto.css.map */
@@ -1 +1 @@
1
- @keyframes smartphoto{from{opacity:0}to{opacity:1}}@keyframes smartphoto-img-wrap{from{opacity:0}to{opacity:1}}@keyframes smartphoto-inner{from{transform:translate(0, 100px)}to{transform:translate(0, 0)}}@keyframes smartphoto-loader{0%{opacity:.4;transform:rotate(0deg)}50%{opacity:1;transform:rotate(180deg)}100%{opacity:.4;transform:rotate(360deg)}}@keyframes smartphoto-appear{0%{opacity:0}100%{opacity:1}}@keyframes smartphoto-hide{0%{opacity:1}100%{opacity:0}}:root:has(dialog.smartphoto[open]){overflow:hidden}.smartphoto{border:none;background:rgba(0,0,0,0);padding:0;margin:0;outline:none;position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden;height:var(--smartphoto-vh, 100dvh);max-height:var(--smartphoto-vh, 100dvh);background-color:var(--smartphoto-backdrop-color, rgb(0, 0, 0));opacity:1;font-family:sans-serif;cursor:pointer;transition:opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out),display var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out) allow-discrete,overlay var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out) allow-discrete}.smartphoto:not([open]){opacity:0}.smartphoto::backdrop{background-color:var(--smartphoto-backdrop-color, rgb(0, 0, 0))}::view-transition-group(smartphoto-hero),::view-transition-old(smartphoto-hero),::view-transition-new(smartphoto-hero){animation-duration:var(--smartphoto-animation-speed, 0.3s);animation-timing-function:var(--smartphoto-animation-function, ease-out)}.smartphoto-close{opacity:0}.smartphoto-count{display:inline-block;color:#fff;font-size:16px}.smartphoto-header{display:block;box-sizing:border-box;position:fixed;z-index:102;top:0;left:0;width:100%;height:50px;padding:15px;background-color:var(--smartphoto-header-color, rgba(0, 0, 0, 0.2))}.smartphoto-content{display:block;position:absolute;top:0;left:0;width:100%;height:100%;touch-action:none}.smartphoto-dismiss{display:block;position:absolute;top:15px;right:10px;width:20px;height:20px;padding:0;border:none;background-color:rgba(0,0,0,0);background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0i44Os44Kk44Ok44O8XzEiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI4MzQuNjUgMjgzNC42NSIgZmlsbD0iI0ZGRiI+PHRpdGxlPmljb248L3RpdGxlPjxwYXRoIGQ9Ik0xNTc2LjQyLDE0MDYuNzYsMjc4NCwxOTkuMTlhNTYuODYsNTYuODYsMCwwLDAsMC04MC4xOGwtNzguOTItNzguOTJhNTYuODYsNTYuODYsMCwwLDAtODAuMTgsMEwxNDE3LjMyLDEyNDcuNjYsMjA5Ljc1LDQwLjA5YTU2Ljg2LDU2Ljg2LDAsMCwwLTgwLjE4LDBMNTAuNjUsMTE5YTU2Ljg2LDU2Ljg2LDAsMCwwLDAsODAuMThMMTI1OC4yMywxNDA2Ljc2LDUwLjY1LDI2MTQuMzRhNTYuODYsNTYuODYsMCwwLDAsMCw4MC4xOGw3OC45Miw3OC45MmE1Ni44Niw1Ni44NiwwLDAsMCw4MC4xOCwwTDE0MTcuMzIsMTU2NS44NiwyNjI0LjksMjc3My40NGE1Ni44Niw1Ni44NiwwLDAsMCw4MC4xOCwwbDc4LjkyLTc4LjkyYTU2Ljg2LDU2Ljg2LDAsMCwwLDAtODAuMThaIi8+PC9zdmc+);text-shadow:0 1px 0 #fff;color:#fff;font-size:30px;text-decoration:none;cursor:pointer;line-height:1}.smartphoto-body{position:relative;z-index:102;width:100%;height:100%;margin:0 auto}.smartphoto-inner{position:relative;width:100%;height:100%;vertical-align:top}.smartphoto-img{display:none;max-width:none;width:auto;height:auto;cursor:zoom-in;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;transition:transform var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);-webkit-user-drag:none}.smartphoto-img.active{display:block}.smartphoto-img-onmove{cursor:grab;cursor:-webkit-grab;transition:none}.smartphoto-img-elasticmove{transition:transform var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out)}.smartphoto-img-wrap{display:inline-block;opacity:1;touch-action:none;-webkit-transition:opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);-moz-transition:opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);-ms-transition:opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);-o-transition:opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);transition:opacity var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out);animation-name:smartphoto-img-wrap;animation-duration:var(--smartphoto-animation-speed, 0.3s);animation-timing-function:var(--smartphoto-animation-function, ease-out)}.smartphoto-img-left{transform:translateX(150%) !important}.smartphoto-img-right{transform:translateX(-150%) !important}.smartphoto-arrows{list-style-type:none;margin:0;padding:0;position:relative;z-index:1002;top:50%;left:0;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed, 0.3s);animation-timing-function:var(--smartphoto-animation-function, ease-out)}.smartphoto-arrows[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows li{display:block;position:absolute;top:50%;width:30px;height:30px;margin-top:-20px;box-sizing:content-box;animation-duration:var(--smartphoto-animation-speed, 0.3s);animation-timing-function:var(--smartphoto-animation-function, ease-out);animation-name:smartphoto-appear}.smartphoto-arrows li:focus{outline:none}.smartphoto-arrows [aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:rgba(0,0,0,0);cursor:pointer}.smartphoto-arrow-right{right:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-right button{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0i44Os44Kk44Ok44O8XzEiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI4MzQuNjUgMjgzNC42NSIgZmlsbD0iI0ZGRiAiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTgzNy44OCwxNDE3LjMyLDY0My41OSwyMjNhNzIuMjEsNzIuMjEsMCwwLDEsMC0xMDEuODJMNzQzLjgyLDIxYTcyLjIxLDcyLjIxLDAsMCwxLDEwMS44MiwwTDIwOTAuODMsMTI2Ni4xOWwxMDAuMjMsMTAwLjIzYTcyLjIxLDcyLjIxLDAsMCwxLDAsMTAxLjgyTDg0NS42NCwyODEzLjY1YTcyLjIxLDcyLjIxLDAsMCwxLTEwMS44MiwwTDY0My41OSwyNzEzLjQyYTcyLjIxLDcyLjIxLDAsMCwxLDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartphoto-arrow-left{left:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-left button{background-image:url(data:image/svg+xml;base64,PHN2ZyBpZD0i44Os44Kk44Ok44O8XzEiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI4MzQuNjUgMjgzNC42NSIgZmlsbD0iI0ZGRiI+PHRpdGxlPmljb248L3RpdGxlPjxwYXRoIGQ9Ik05OTYuNzcsMTQxNy4zMiwyMTkxLjA2LDIyM2E3Mi4yMSw3Mi4yMSwwLDAsMCwwLTEwMS44MkwyMDkwLjgzLDIxQTcyLjIxLDcyLjIxLDAsMCwwLDE5ODksMjFMNzQzLjgyLDEyNjYuMTksNjQzLjU5LDEzNjYuNDJhNzIuMjEsNzIuMjEsMCwwLDAsMCwxMDEuODJMMTk4OSwyODEzLjY1YTcyLjIxLDcyLjIxLDAsMCwwLDEwMS44MiwwbDEwMC4yMy0xMDAuMjNhNzIuMjEsNzIuMjEsMCwwLDAsMC0xMDEuODJaIi8+PC9zdmc+)}.smartPhotoArrowHideIcon{display:none}.smartphoto-nav{position:absolute;bottom:0;left:0;width:100%;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed, 0.3s);animation-timing-function:var(--smartphoto-animation-function, ease-out)}.smartphoto-nav[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-nav ul{display:block;overflow-x:auto;list-style:none;margin:0;padding:0;text-align:center;white-space:nowrap;-webkit-overflow-scrolling:touch}.smartphoto-nav li{display:inline-block;overflow:hidden;width:50px;height:50px}.smartphoto-nav button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:#fff;background-position:center center;background-size:cover;opacity:.5;cursor:pointer}.smartphoto-nav button:focus{opacity:.8}.smartphoto-nav button.current{opacity:1}.smartphoto-nav img{width:auto;height:100%}.smartphoto-list{list-style-type:none;position:absolute;z-index:101;top:0;left:0;margin:0;padding:0;white-space:nowrap}.smartphoto-list li{display:block;position:absolute;top:0;left:0;width:100%;height:100%;transition:all var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out)}.smartphoto-list li:focus{outline:none}.smartphoto-list-onmove{transition:all .3s var(--smartphoto-animation-function, ease-out)}.smartphoto-caption{overflow:hidden;box-sizing:border-box;position:absolute;top:0;left:0;width:100%;height:50px;padding:0 50px;color:#fff;font-size:12px;text-align:center;line-height:50px;white-space:nowrap;text-overflow:ellipsis;margin:0;font-weight:normal}.smartphoto-caption:focus{outline:none}.smartphoto-loader-wrap{display:block;position:relative;z-index:103;width:0;height:0;transform:translate(50vw, 50vh);transform:translate(50vw, 50dvh);transform:translate(50vw, calc(var(--smartphoto-vh, 100dvh) / 2))}.smartphoto-loader{position:absolute;z-index:101;top:0;left:0;width:30px;height:30px;margin-top:-25px;margin-left:-25px;border:8px solid #17cddd;border-right-color:rgba(0,0,0,0);border-radius:50%;animation:smartphoto-loader .5s infinite linear}.smartphoto-img-clone{position:fixed;z-index:100;top:0;left:0;transition:all var(--smartphoto-animation-speed, 0.3s) var(--smartphoto-animation-function, ease-out)}.smartphoto-sr-only{overflow:hidden;position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0, 0, 0, 0)}
1
+ @keyframes smartphoto{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-img-wrap{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-inner{0%{transform:translateY(100px)}to{transform:translate(0)}}@keyframes smartphoto-loader{0%{opacity:.4;transform:rotate(0deg)}50%{opacity:1;transform:rotate(180deg)}to{opacity:.4;transform:rotate(1turn)}}@keyframes smartphoto-appear{0%{opacity:0}to{opacity:1}}@keyframes smartphoto-hide{0%{opacity:1}to{opacity:0}}:root:has(dialog.smartphoto[open]){overflow:hidden}.smartphoto{border:none;background:transparent;padding:0;margin:0;outline:none;position:fixed;inset:0;width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden;height:var(--smartphoto-vh,100dvh);max-height:var(--smartphoto-vh,100dvh);background-color:var(--smartphoto-backdrop-color,#000);opacity:1;font-family:sans-serif;cursor:pointer;transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out),display var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out) allow-discrete,overlay var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out) allow-discrete}.smartphoto:not([open]){opacity:0}.smartphoto::backdrop{background-color:var(--smartphoto-backdrop-color,#000)}::view-transition-group(smartphoto-hero),::view-transition-new(smartphoto-hero),::view-transition-old(smartphoto-hero){animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-close{opacity:0}.smartphoto-count{display:inline-block;color:#fff;font-size:16px}.smartphoto-header{display:block;box-sizing:border-box;position:fixed;z-index:102;top:0;left:0;width:100%;height:50px;padding:15px;background-color:var(--smartphoto-header-color,rgba(0,0,0,.2))}.smartphoto-content{display:block;position:absolute;top:0;left:0;width:100%;height:100%;touch-action:none}.smartphoto-dismiss{display:block;position:absolute;top:15px;right:10px;width:20px;height:20px;padding:0;border:none;background-color:transparent;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTU3Ni40MiAxNDA2Ljc2IDI3ODQgMTk5LjE5YTU2Ljg2IDU2Ljg2IDAgMCAwIDAtODAuMThsLTc4LjkyLTc4LjkyYTU2Ljg2IDU2Ljg2IDAgMCAwLTgwLjE4IDBMMTQxNy4zMiAxMjQ3LjY2IDIwOS43NSA0MC4wOWE1Ni44NiA1Ni44NiAwIDAgMC04MC4xOCAwTDUwLjY1IDExOWE1Ni44NiA1Ni44NiAwIDAgMCAwIDgwLjE4bDEyMDcuNTggMTIwNy41OEw1MC42NSAyNjE0LjM0YTU2Ljg2IDU2Ljg2IDAgMCAwIDAgODAuMThsNzguOTIgNzguOTJhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGwxMjA3LjU3LTEyMDcuNThMMjYyNC45IDI3NzMuNDRhNTYuODYgNTYuODYgMCAwIDAgODAuMTggMGw3OC45Mi03OC45MmE1Ni44NiA1Ni44NiAwIDAgMCAwLTgwLjE4WiIvPjwvc3ZnPg==);text-shadow:0 1px 0 #fff;color:#fff;font-size:30px;text-decoration:none;cursor:pointer;line-height:1}.smartphoto-body{z-index:102;margin:0 auto}.smartphoto-body,.smartphoto-inner{position:relative;width:100%;height:100%}.smartphoto-inner{vertical-align:top}.smartphoto-img{display:none;max-width:none;width:auto;height:auto;cursor:zoom-in;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;transition:transform var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-webkit-user-drag:none}.smartphoto-img.active{display:block}.smartphoto-img-onmove{cursor:grab;cursor:-webkit-grab;transition:none}.smartphoto-img-elasticmove{transition:transform var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-img-wrap{display:inline-block;opacity:1;touch-action:none;-webkit-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-moz-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-ms-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);-o-transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);transition:opacity var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out);animation-name:smartphoto-img-wrap;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-img-left{transform:translateX(150%)!important}.smartphoto-img-right{transform:translateX(-150%)!important}.smartphoto-arrows{list-style-type:none;margin:0;padding:0;position:relative;z-index:1002;top:50%;left:0;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-arrows[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows li{display:block;position:absolute;top:50%;width:30px;height:30px;margin-top:-20px;box-sizing:content-box;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out);animation-name:smartphoto-appear}.smartphoto-arrows li:focus{outline:none}.smartphoto-arrows [aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-arrows button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:transparent;cursor:pointer}.smartphoto-arrow-right{right:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-right button{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNMTgzNy44OCAxNDE3LjMyIDY0My41OSAyMjNhNzIuMjEgNzIuMjEgMCAwIDEgMC0xMDEuODJMNzQzLjgyIDIxYTcyLjIxIDcyLjIxIDAgMCAxIDEwMS44MiAwbDEyNDUuMTkgMTI0NS4xOSAxMDAuMjMgMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAxIDAgMTAxLjgyTDg0NS42NCAyODEzLjY1YTcyLjIxIDcyLjIxIDAgMCAxLTEwMS44MiAwbC0xMDAuMjMtMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAxIDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartphoto-arrow-left{left:0;padding:5px 0;background-color:rgba(0,0,0,.5)}.smartphoto-arrow-left button{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiNmZmYiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDEiIHZpZXdCb3g9IjAgMCAyODM0LjY1IDI4MzQuNjUiPjx0aXRsZT5pY29uPC90aXRsZT48cGF0aCBkPSJNOTk2Ljc3IDE0MTcuMzIgMjE5MS4wNiAyMjNhNzIuMjEgNzIuMjEgMCAwIDAgMC0xMDEuODJMMjA5MC44MyAyMUE3Mi4yMSA3Mi4yMSAwIDAgMCAxOTg5IDIxTDc0My44MiAxMjY2LjE5bC0xMDAuMjMgMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAwIDAgMTAxLjgyTDE5ODkgMjgxMy42NWE3Mi4yMSA3Mi4yMSAwIDAgMCAxMDEuODIgMGwxMDAuMjMtMTAwLjIzYTcyLjIxIDcyLjIxIDAgMCAwIDAtMTAxLjgyWiIvPjwvc3ZnPg==)}.smartPhotoArrowHideIcon{display:none}.smartphoto-nav{position:absolute;bottom:0;left:0;width:100%;opacity:1;animation-name:smartphoto-appear;animation-duration:var(--smartphoto-animation-speed,.45s);animation-timing-function:var(--smartphoto-animation-function,ease-out)}.smartphoto-nav[aria-hidden=true]{animation-name:smartphoto-hide;display:none}.smartphoto-nav ul{display:block;overflow-x:auto;list-style:none;margin:0;padding:0;text-align:center;white-space:nowrap;-webkit-overflow-scrolling:touch}.smartphoto-nav li{display:inline-block;overflow:hidden;width:50px;height:50px}.smartphoto-nav button{appearance:none;display:block;width:100%;height:100%;margin:0;padding:0;border:none;background-color:#fff;background-position:50%;background-size:cover;opacity:.5;cursor:pointer}.smartphoto-nav button:focus{opacity:.8}.smartphoto-nav button.current{opacity:1}.smartphoto-nav img{width:auto;height:100%}.smartphoto-list{list-style-type:none;position:absolute;z-index:101;top:0;left:0;margin:0;padding:0;white-space:nowrap}.smartphoto-list li{display:block;position:absolute;top:0;left:0;width:100%;height:100%;transition:all var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-list li:focus{outline:none}.smartphoto-list-onmove{transition:all .3s var(--smartphoto-animation-function,ease-out)}.smartphoto-caption{overflow:hidden;box-sizing:border-box;position:absolute;top:0;left:0;width:100%;height:50px;padding:0 50px;color:#fff;font-size:12px;text-align:center;line-height:50px;white-space:nowrap;text-overflow:ellipsis;margin:0;font-weight:400}.smartphoto-caption:focus{outline:none}.smartphoto-loader-wrap{display:block;position:relative;z-index:103;width:0;height:0;transform:translate(50vw,50vh);transform:translate(50vw,50dvh);transform:translate(50vw,calc(var(--smartphoto-vh, 100dvh)/2))}.smartphoto-loader{position:absolute;z-index:101;top:0;left:0;width:30px;height:30px;margin-top:-25px;margin-left:-25px;border:8px solid #17cddd;border-right-color:transparent;border-radius:50%;animation:smartphoto-loader .5s linear infinite}.smartphoto-img-clone{position:fixed;z-index:100;top:0;left:0;transition:all var(--smartphoto-animation-speed,.45s) var(--smartphoto-animation-function,ease-out)}.smartphoto-sr-only{overflow:hidden;position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0,0,0,0)}