polite-media 0.5.0 → 0.6.0

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/CHANGELOG.md CHANGED
@@ -3,6 +3,84 @@
3
3
  Notable changes, newest first. Versions follow [semver](https://semver.org); while
4
4
  this is `0.x`, a minor bump may still break things and will say so here.
5
5
 
6
+ ## 0.6.0 (2026-10-07)
7
+
8
+ ### Breaking
9
+
10
+ - **`data-polite-active` is on `<html>` only while a registered video may play.** It used to stay
11
+ for as long as any video was registered, so under reduced motion, on Save-Data or a 2g connection,
12
+ or with `atOnce` at `0`, the README's recipe showed a pause control with nothing to stop. It now
13
+ follows those gates on every reconcile, and a user pause keeps it, since the control is then what
14
+ resumes. CSS that used the attribute to mean "a video is registered" needs another hook.
15
+
16
+ - **A revealed poster is hidden with `opacity`, so its `alt` stays in the accessibility tree.**
17
+ `video.css` hid it with `visibility: hidden`, which removes it from the tree, while the README
18
+ tells you to put the meaning in the poster's `alt` and hide the video. It now sets
19
+ `opacity: 0 !important` and `pointer-events: none` on the poster image, inside a `<picture>` too,
20
+ after the same `--polite-fade` delay. `!important` because image.css's failsafe animation would
21
+ otherwise keep a marked poster that nothing manages opaque. A rule of yours that changes the
22
+ poster's opacity after the reveal now needs `!important` as well, and a test that waited for the
23
+ poster with Playwright's `toBeHidden()` must wait for computed opacity `0`, since Playwright
24
+ counts an element at opacity 0 as visible.
25
+
26
+ - **`smallViewport` defaults to `'(max-width: 767.98px)'`**, from `'(max-width: 767px)'`. Beside a
27
+ `(min-width: 768px)` the old default left every width between 767px and 768px, which page zoom
28
+ produces, matching neither, so arbitration treated those viewports as large. The gap is now
29
+ 0.02px. Range syntax would close it fully, but Safari before 16.4 never matches it. Pass
30
+ `smallViewport` yourself to keep the old value.
31
+
32
+ ### Added
33
+
34
+ - **A warning when a registered video is not decorative.** The markup contract asks for
35
+ `tabindex="-1" aria-hidden="true"` on the video, and nothing checked it. `register()` now warns
36
+ once per page, naming the video, when its `tabindex` attribute is not `-1` or no
37
+ `aria-hidden="true"` sits on the video or a box around it.
38
+
39
+ - **A warning when `--polite-fade` is not a CSS time.** A value such as `0.6` computes to `0s`
40
+ rather than to the stylesheet's default, so it silently removed the image fade. The first video
41
+ box and the first fading image that see such a value are named once per page. The browser parses
42
+ the value, so `calc(0.3s * 2)` passes, and a bare `0` stays quiet because it gives the cut it
43
+ looks like.
44
+
45
+ - **`register(video, { until, prefetchWhileGated: true })`** lets a gated video download while it
46
+ waits, so a splash buys it load time. A gate used to hold the fetch as well as playback, and that
47
+ stays the default, since a page may rely on a consent dialog holding the bytes too. The download
48
+ still waits for `startWhen`, reduced motion, Save-Data and a user pause, and starts once the video
49
+ is on screen or within `prefetchMargin`. A host can end its splash on the video's own
50
+ `canplaythrough`, which fires while the gate still holds; the README shows the recipe.
51
+
52
+ ### Fixed
53
+
54
+ - **`warm()` with `sources` fetched the candidate for the full viewport width.** A `<source>`
55
+ without its own `sizes` is selected as if it said `100vw`, and `sizes` went on the `<img>` alone,
56
+ so a desktop warm could fetch a file several times the size the destination then picked. Every
57
+ `<source>` now carries the `sizes` it was passed.
58
+
59
+ - **A video buffered ahead through `prefetchMargin` started playing off screen when its first source
60
+ could not be decoded.** The source fallback revealed and played whatever came next, whether or not
61
+ anything had asked the video to play. It now moves to the next source and waits.
62
+
63
+ - **A lazy image still faded in under reduced motion.** `image.css`'s reduced-motion rule lost on
64
+ specificity to the rule that sets the fade, so the README's promise that reduced motion overrides
65
+ `--polite-fade` held only for eager images that opted in. Lazy images now arrive at once there.
66
+
67
+ - **A paused page still buffered videos within `prefetchMargin`.** The prefetch observer fetched
68
+ without asking whether the visitor had paused. It now waits, and resuming starts the fetch.
69
+
70
+ ### Documentation
71
+
72
+ - **`register()` and `pauseAll()` carry their documentation in the published types.** Their doc
73
+ comments sat above other functions, so an editor hovering either showed nothing.
74
+
75
+ - **An `until` gate does not protect LCP**, and the README no longer says it does. The video's
76
+ first frame is an LCP candidate whenever it paints; only `startWhen: 'interaction'` keeps it out.
77
+ The poster-`load` gate example is gone for the same reason.
78
+ - **A gate that never settles holds its video for good.** The README shows racing it against a
79
+ timeout of your own.
80
+ - **The wrapper recipe in "Composing your own animation" gates only on images that will load.**
81
+ Lazy images in a horizontal scroller may never be fetched, so a wrapper waiting on all of them
82
+ waits for its failsafe.
83
+
6
84
  ## 0.5.0 (2026-09-12)
7
85
 
8
86
  ### Breaking
package/README.md CHANGED
@@ -166,9 +166,12 @@ console names any image in that state, so widen the selector or drop the
166
166
  attribute. An eager image is never hidden; give the attribute the value `eager`
167
167
  to opt one into the fade anyway.
168
168
 
169
- `data-polite-active` is on `<html>` for as long as at least one video is
170
- registered. A pause control is markup on every page, but it must not offer to
171
- stop something that was never registered, and nothing else lets CSS answer that:
169
+ `data-polite-active` is on `<html>` while a registered video may play. It is
170
+ absent when nothing is registered, under reduced motion, on Save-Data or a 2g
171
+ connection, and where `atOnce` is `0` for the viewport; a user pause keeps it,
172
+ since the control is then what resumes. A pause control is markup on every page,
173
+ but it must not offer to stop something that cannot move, and CSS alone cannot
174
+ see most of those reasons:
172
175
 
173
176
  ```css
174
177
  [data-polite-pause-control] {
@@ -207,6 +210,14 @@ bundle that never arrives leaves your wrapper hidden for good even though the
207
210
  library's own failsafe fired. Give any rule of yours that hides on
208
211
  `:not([data-polite-ready])` its own failsafe on the same delay.
209
212
 
213
+ **Gate a wrapper only on images that will load.** The `:has()` above waits on
214
+ every marked image inside the card, and lazy loading may never fetch some of
215
+ them. Measured in Chromium, in a 412px-wide horizontal scroller of nine lazy
216
+ images, only the first three loaded, and three in the middle never did, even
217
+ after scrolling past them. A card holding that scroller waits for your failsafe
218
+ and then appears unfaded. Gate it on the images in view when it appears, such as
219
+ the first, or leave scrollers out of the rule.
220
+
210
221
  One limit worth knowing: a skipped `content-visibility: auto` subtree runs no
211
222
  animations, so neither failsafe fires there until the section is scrolled into
212
223
  view. It resolves itself the moment anyone looks at it, which is the only moment
@@ -249,14 +260,18 @@ it could have mattered.
249
260
  6. The video carries `tabindex="-1" aria-hidden="true"`. It is decorative, and
250
261
  without this it lands in the tab order: measured in Firefox, twelve background
251
262
  videos sat ahead of the pause button, so a keyboard user reached it on the
252
- thirteenth Tab.
263
+ thirteenth Tab. The console says so once per page when a registered video
264
+ lacks either; `aria-hidden` on a box around it counts too. Anything the
265
+ picture means goes in the poster's `alt`: the reveal hides the poster with
266
+ `opacity`, not `visibility`, so it stays in the accessibility tree while the
267
+ video plays.
253
268
 
254
269
  ## API
255
270
 
256
271
  ```js
257
272
  // polite-media/video
258
- register(video, { until, observe, startWhen }); // manage a video
259
- registerAll(target?, { until, startWhen }); // every [data-polite-media] video by default
273
+ register(video, { until, observe, startWhen, prefetchWhileGated }); // manage a video
274
+ registerAll(target?, { until, startWhen, prefetchWhileGated }); // every [data-polite-media] video by default
260
275
  unregister(video); // stop managing it, release everything
261
276
  unregisterAll(); // tear down the whole page
262
277
  configure({ ... }); // before the first register, or it throws
@@ -309,7 +324,13 @@ rather than guessed.
309
324
  | option | default | reach for it when |
310
325
  | --------------- | ---------------------------- | ---------------------------------------------------------- |
311
326
  | `atOnce` | `{ small: 1, large: 'all' }` | a feed wants one at a time everywhere, or phones want none |
312
- | `smallViewport` | `'(max-width: 767px)'` | your breakpoint is not ours |
327
+ | `smallViewport` | `'(max-width: 767.98px)'` | your breakpoint is not ours |
328
+
329
+ The `smallViewport` default meets a `(min-width: 768px)` with a 0.02px gap rather
330
+ than a whole pixel, so a fractional width from page zoom lands on one side. Pair
331
+ your own queries the same way. Range syntax, `(width < 768px)`, would close the
332
+ gap entirely, but Safari before 16.4 never matches it, so phones there would
333
+ count as large and play every visible video at once.
313
334
 
314
335
  **When may it begin?**
315
336
 
@@ -338,30 +359,70 @@ effect on the next pass.
338
359
  callers: a `2` would otherwise fall through to the single-slot branch and quietly
339
360
  mean `1`.
340
361
 
341
- **A malformed `smallViewport` cannot be detected.** An invalid media query does
342
- not throw and does not normalise to anything recognisable; Chromium echoes the
343
- text straight back and never matches. So `smallViewport: '(max-width: 767)'`,
362
+ **A malformed `smallViewport` is not checked for you.** An invalid media query
363
+ does not throw and does not normalise to anything recognisable; Chromium echoes
364
+ the text straight back and never matches. So `smallViewport: '(max-width: 767)'`,
344
365
  missing its unit, means arbitration silently never engages and phones behave like
345
- desktops. Check that value by eye.
366
+ desktops. Check it in the console on both sides of your breakpoint:
367
+ `matchMedia(query).matches` should be `true` below it and `false` above. A
368
+ malformed query is `false` on both.
346
369
 
347
370
  ### Per-video gates
348
371
 
349
372
  `register(video, { until: promise })` holds a video back until the promise
350
- settles: for a splash screen, a consent dialog, or protecting your LCP. A hero at
351
- scroll-top is reported visible in the observer's very first batch, so without
352
- this it starts before whatever the page is waiting on has finished.
373
+ settles: for a splash screen or a consent dialog. A hero at scroll-top is
374
+ reported visible in the observer's very first batch, so without this it starts
375
+ before whatever the page is waiting on has finished.
376
+
377
+ **A gate delays the video; it does not keep it out of Largest Contentful Paint.**
378
+ The first frame is an LCP candidate like any image, whenever it paints: measured
379
+ in Chromium on a real hero gated behind a splash, the video's first frame
380
+ replaced the poster as the LCP element just after the gate opened. Only
381
+ [`startWhen: 'interaction'`](#startwhen) keeps a video out of LCP.
382
+
383
+ The gate opens when the promise settles, fulfilled or rejected, and not
384
+ otherwise: one that never settles holds the video on its poster for the life of
385
+ the page. If whatever resolves it might never run, race it against a timeout of
386
+ your own:
353
387
 
354
388
  ```js
355
- // If the poster is your LCP element, gate the video on it having loaded.
356
- register(video, {
357
- until: new Promise((done) => {
358
- const poster = document.querySelector('img.hero-poster');
359
- if (!poster || poster.complete) done();
360
- else poster.addEventListener('load', () => done(), { once: true });
361
- }),
362
- });
389
+ const timeout = (ms) => new Promise((done) => setTimeout(done, ms));
390
+
391
+ register(video, { until: Promise.race([splashDone, timeout(15000)]) });
363
392
  ```
364
393
 
394
+ **A splash can buy the video load time.** A gate holds the download as well as
395
+ playback, so a hero behind a five-second splash only starts fetching once the
396
+ splash ends. `prefetchWhileGated: true` lets it download while it waits: only
397
+ playback waits for the gate, while `startWhen`, reduced motion, Save-Data and a
398
+ pause still hold the fetch. The browser fires `canplaythrough` once it can play
399
+ through, which a splash can end on, with a floor and a cap of its own:
400
+
401
+ ```js
402
+ const wait = (ms) => new Promise((done) => setTimeout(done, ms));
403
+ let endSplash;
404
+ const splashDone = new Promise((done) => (endSplash = done));
405
+
406
+ register(hero, { until: splashDone, prefetchWhileGated: true });
407
+
408
+ // Nothing downloads where nothing will play (reduced motion, Save-Data,
409
+ // atOnce: 0), or while the visitor has paused.
410
+ const root = document.documentElement;
411
+ const buffered =
412
+ root.hasAttribute('data-polite-active') && !root.hasAttribute('data-polite-paused')
413
+ ? new Promise((done) => hero.addEventListener('canplaythrough', done, { once: true }))
414
+ : Promise.resolve();
415
+
416
+ // At least 1.5s of splash, at most 4.5s, and in between until the hero can play through.
417
+ await Promise.race([Promise.all([buffered, wait(1500)]), wait(4500)]);
418
+ hideSplash();
419
+ endSplash();
420
+ ```
421
+
422
+ Keep the cap. Whether iOS Safari buffers under `preload="auto"` before anything
423
+ calls `play()` is untested, and the cap is what ends the splash if the event
424
+ never comes.
425
+
365
426
  `register(video, { observe: box })` observes a wrapper instead of the video, for
366
427
  when the video is `inset: 0` inside the element that carries the layout.
367
428
 
@@ -562,7 +623,9 @@ Two things that surprise people:
562
623
  that is invalid at computed-value time falls back to the property's initial
563
624
  value, and the `var()` fallback only applies when the property is undefined.
564
625
  Harmless on video, which cuts anyway; on images it silently removes the 350ms
565
- fade.
626
+ fade. The console names the first image or video box where it is set to
627
+ something that is not a time. A bare `0` is left alone, since the cut it gives
628
+ is what it looks like it asks for.
566
629
 
567
630
  Reduced motion overrides you either way: the stylesheet sets `transition: none`
568
631
  there, so a fade you asked for never runs for someone who asked not to see one.
@@ -585,6 +648,11 @@ warmOnIntent('a[data-hero]', (link) => ({
585
648
  }));
586
649
  ```
587
650
 
651
+ Give a format through `sources` with its `type`, as above, rather than as a bare `srcset`: a
652
+ browser that cannot decode AVIF then skips it and warms the fallback, instead of fetching a file it
653
+ cannot show. `sizes` goes on every `<source>` and on the image, since a `<source>` without its own
654
+ is chosen as if it said `100vw`.
655
+
588
656
  **Nothing in this package parses a media query**, which is the point: the
589
657
  candidates are assembled as a detached `<picture>` and the browser picks, running
590
658
  the same algorithm it will run on the destination. Hand-rolling that selection
@@ -633,6 +701,24 @@ document.addEventListener('astro:page-load', () => registerAll('[data-polite-med
633
701
  registered twice. Videos that did not survive need no cleanup: the coordinator
634
702
  drops any entry whose element has left the document on its next pass.
635
703
 
704
+ ## Astro
705
+
706
+ This is developed against Astro projects, and the same three things come up.
707
+
708
+ **Import each stylesheet from the component that emits its attribute.** A build folds every
709
+ component's CSS into one file, so a stylesheet imported anywhere covers everywhere, while a dev
710
+ server serves it per component and does not. Import `image.css` from some other component and the
711
+ fade works in the build and is missing in dev, on exactly the pages that do not render whichever
712
+ component happened to import it. The console says so when the stylesheet never arrives.
713
+
714
+ **Put the `<script>` in the component that renders the media**, not in the layout. Astro bundles a
715
+ component's script once per page, so a page that never renders that component never downloads the
716
+ coordinator.
717
+
718
+ **A strict CSP needs nothing from this package.** It writes attributes and never an inline `style`,
719
+ which the end-to-end suite asserts on every demo, so `style-src` needs no `'unsafe-inline'` on its
720
+ account.
721
+
636
722
  ## What it does
637
723
 
638
724
  - Reveals on a genuinely presented frame, never on `playing`.
@@ -52,8 +52,13 @@ export interface ConfigureOptions {
52
52
  */
53
53
  prefetchMargin?: string;
54
54
  /**
55
- * Which viewports count as small. Configurable because 767px is one project's
55
+ * Which viewports count as small. Configurable because 768px is one project's
56
56
  * breakpoint, not a fact about phones.
57
+ *
58
+ * The default stops at 767.98px, leaving 0.02px beside a `(min-width: 768px)`
59
+ * rather than the whole pixel a zoomed page's fractional width can fall into.
60
+ * Range syntax would close the gap, but Safari before 16.4 never matches it, so
61
+ * phones there would count as large.
57
62
  */
58
63
  smallViewport?: string;
59
64
  /**
@@ -158,6 +163,9 @@ export interface RegisterOptions {
158
163
  * at scroll-top is reported visible in the observer's very first batch, so
159
164
  * without a gate it starts before whatever the page is waiting on (a splash
160
165
  * screen, a consent dialog) has finished.
166
+ *
167
+ * Settling, fulfilled or rejected, is the only release: a promise that never
168
+ * settles holds the video on its poster for the life of the page.
161
169
  */
162
170
  until?: Promise<unknown>;
163
171
  /**
@@ -173,8 +181,30 @@ export interface RegisterOptions {
173
181
  * the same rule buys nothing.
174
182
  */
175
183
  startWhen?: StartWhen;
184
+ /**
185
+ * Let the video download while `until` holds it, so a splash buys it load time.
186
+ * Only playback waits for the gate; the download still waits for `startWhen`,
187
+ * Save-Data, reduced motion and a user pause, and starts once the video is on
188
+ * screen or within `prefetchMargin`.
189
+ *
190
+ * Opt-in, because a gate holding the fetch too is what `until` has always
191
+ * done, and a page gating a video behind a consent dialog may rely on it.
192
+ */
193
+ prefetchWhileGated?: boolean;
176
194
  }
177
195
  export declare function reconcile(): void;
196
+ /**
197
+ * Starts managing a video: reveals it on its first genuinely painted frame,
198
+ * plays it only while it is visible, falls through its `<source>` list when one
199
+ * cannot be decoded, and stops it when a gate closes.
200
+ *
201
+ * The video and its poster must already share a box carrying `data-polite-media`
202
+ * in the authored markup, and the video should be `muted loop playsinline
203
+ * preload="none"`. Calling this twice on the same element is a no-op.
204
+ *
205
+ * @param video the element to manage
206
+ * @param options see {@link RegisterOptions}
207
+ */
178
208
  export declare function register(video: HTMLVideoElement, options?: RegisterOptions): void;
179
209
  /** Anything that names one or more videos. See {@link Target}. */
180
210
  export type VideoTarget = Target<HTMLVideoElement>;
@@ -199,6 +229,22 @@ export declare function registerAll(target?: VideoTarget, options?: Omit<Registe
199
229
  * was the last one. Safe to call for a video that was never registered.
200
230
  */
201
231
  export declare function unregister(video: HTMLVideoElement): void;
232
+ /**
233
+ * Stops every managed video and keeps them stopped.
234
+ *
235
+ * WCAG 2.2.2 applies to content that moves automatically, runs for more than
236
+ * five seconds, and sits alongside other content -- which a looping background
237
+ * video does. Honouring `prefers-reduced-motion` is necessary but, per the W3C
238
+ * understanding document, is not listed as satisfying the criterion, so a
239
+ * mechanism the user can actually operate has to exist.
240
+ *
241
+ * The host supplies the button and its styling; the library ships no markup and
242
+ * no CSS for it. A `<button>` carrying `data-polite-pause-control` toggles this.
243
+ *
244
+ * It has to be a real `<button>`. The binding is a delegated `click`, and a
245
+ * browser only synthesises that from Enter and Space for a native button, so a
246
+ * `div[role="button"][tabindex="0"]` responds to a mouse and not to a keyboard.
247
+ */
202
248
  export declare function pauseAll(): void;
203
249
  /** Lets playback resume, undoing {@link pauseAll}. */
204
250
  export declare function resumeAll(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator.d.ts","sourceRoot":"","sources":["../src/coordinator.ts"],"names":[],"mappings":"AAWA,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3D;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4ED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAcvD;AAwDD,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAkjBD,wBAAgB,SAAS,IAAI,IAAI,CAsFhC;AAiPD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,GAAE,eAAoB,GAAG,IAAI,CA6DrF;AAED,kEAAkE;AAClE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,MAAM,GAAE,WAAyC,EACjD,OAAO,GAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAM,GAC7C,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAwBxD;AAiED,wBAAgB,QAAQ,IAAI,IAAI,CAG/B;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,IAAI,CAGhC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAErF"}
1
+ {"version":3,"file":"coordinator.d.ts","sourceRoot":"","sources":["../src/coordinator.ts"],"names":[],"mappings":"AAYA,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3D;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,CAAC;AAElE;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA4ED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAcvD;AA0DD,MAAM,WAAW,eAAe;IAC9B;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACzB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AA0lBD,wBAAgB,SAAS,IAAI,IAAI,CA4FhC;AAmOD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,GAAE,eAAoB,GAAG,IAAI,CAgErF;AAED,kEAAkE;AAClE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CACzB,MAAM,GAAE,WAAyC,EACjD,OAAO,GAAE,IAAI,CAAC,eAAe,EAAE,SAAS,CAAM,GAC7C,IAAI,CAEN;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAwBxD;AAiDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,IAAI,IAAI,CAG/B;AAED,sDAAsD;AACtD,wBAAgB,SAAS,IAAI,IAAI,CAGhC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAIpC;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAErF"}