accessify-widget 0.3.74 → 0.3.76

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.
@@ -4,105 +4,34 @@ function createAnimationStopModule() {
4
4
  const STORAGE_KEY = "accessify-animation-stop";
5
5
  let mutationObserver = null;
6
6
  let scanInterval = null;
7
- let scrollHandler = null;
8
7
  let originalVideoPlay = null;
9
8
  let originalAnimate = null;
10
- let pausedVideos = [];
11
9
  let gifOriginals = /* @__PURE__ */ new Map();
12
- const VISUAL_ONLY_PROPS = /* @__PURE__ */ new Set([
13
- "transform",
14
- "scale",
15
- "rotate",
16
- "translate",
17
- "filter",
18
- "backdropFilter",
19
- "backdrop-filter",
20
- "webkitTransform",
21
- "webkitFilter",
22
- "-webkit-transform",
23
- "-webkit-filter",
24
- "offset",
25
- "easing",
26
- "composite"
27
- ]);
28
- function isVisualOnlyKeyframes(keyframes) {
29
- if (!keyframes) return false;
10
+ let debounceTimer = null;
11
+ let delayedTimers = [];
12
+ const WIDGET_SEL = ":not(#accessify-root):not(#accessify-root *)";
13
+ function isWidgetElement(el) {
30
14
  try {
31
- if (Array.isArray(keyframes)) {
32
- for (const kf of keyframes) {
33
- if (!kf || typeof kf !== "object") return false;
34
- for (const key of Object.keys(kf)) {
35
- if (!VISUAL_ONLY_PROPS.has(key)) return false;
36
- }
37
- }
38
- return true;
39
- }
40
- for (const key of Object.keys(keyframes)) {
41
- if (!VISUAL_ONLY_PROPS.has(key)) return false;
15
+ let node = el;
16
+ while (node) {
17
+ if (node.id === "accessify-root") return true;
18
+ const parent = node.parentNode || node.host || null;
19
+ if (parent === node) break;
20
+ node = parent;
42
21
  }
43
- return true;
44
22
  } catch {
45
- return false;
46
- }
47
- }
48
- function patchAnimate() {
49
- if (originalAnimate) return;
50
- originalAnimate = Element.prototype.animate;
51
- Element.prototype.animate = function(keyframes, options) {
52
- if (!enabled) {
53
- return originalAnimate.call(this, keyframes, options);
54
- }
55
- try {
56
- let node = this;
57
- while (node) {
58
- if (node.id === "accessify-root") {
59
- return originalAnimate.call(this, keyframes, options);
60
- }
61
- const parent = node.parentNode || node.host;
62
- if (parent === node) break;
63
- node = parent;
64
- }
65
- } catch {
66
- }
67
- const visualOnly = isVisualOnlyKeyframes(keyframes);
68
- let opts;
69
- if (typeof options === "number") {
70
- opts = { duration: 1e-3, fill: "forwards" };
71
- } else {
72
- opts = {
73
- ...options || {},
74
- duration: 1e-3,
75
- delay: 0,
76
- iterations: 1,
77
- fill: "forwards"
78
- };
79
- delete opts.iterationStart;
80
- delete opts.endDelay;
81
- }
82
- const anim = originalAnimate.call(this, keyframes, opts);
83
- try {
84
- if (visualOnly) {
85
- anim.cancel();
86
- } else {
87
- anim.finish();
88
- }
89
- } catch {
90
- }
91
- return anim;
92
- };
93
- }
94
- function restoreAnimate() {
95
- if (originalAnimate) {
96
- Element.prototype.animate = originalAnimate;
97
- originalAnimate = null;
98
23
  }
24
+ return false;
99
25
  }
100
26
  function injectStyles() {
101
27
  if (document.getElementById(STYLE_ID)) return;
102
28
  const style = document.createElement("style");
103
29
  style.id = STYLE_ID;
104
30
  style.textContent = `
105
- *, *::before, *::after {
31
+ /* --- Kill all CSS-driven animations & transitions --- */
32
+ *${WIDGET_SEL},
33
+ *${WIDGET_SEL}::before,
34
+ *${WIDGET_SEL}::after {
106
35
  animation-duration: 0.001ms !important;
107
36
  animation-iteration-count: 1 !important;
108
37
  animation-delay: 0s !important;
@@ -113,15 +42,36 @@ function createAnimationStopModule() {
113
42
  animation-timeline: auto !important;
114
43
  scroll-timeline: none !important;
115
44
  }
116
- /* Neutralize interaction transforms (hover zoom, click scale, focus
117
- lift). Without this, CSS like \`.card:hover { transform: scale(1.05) }\`
118
- still visibly changes the element — just instantly. Users who
119
- disable animations expect NO motion including the end-state. */
120
- *:not(#accessify-root):not(#accessify-root *):hover,
121
- *:not(#accessify-root):not(#accessify-root *):focus,
122
- *:not(#accessify-root):not(#accessify-root *):focus-within,
123
- *:not(#accessify-root):not(#accessify-root *):focus-visible,
124
- *:not(#accessify-root):not(#accessify-root *):active {
45
+
46
+ /* --- Force Framer appear-elements visible --- *
47
+ * Framer sets inline opacity:0.001 + transform:translateY(...)
48
+ * on elements waiting for scroll/appear animations. We override
49
+ * with !important which beats inline styles. When animation-stop
50
+ * is deactivated, removing this stylesheet instantly restores
51
+ * Framer's inline values — no cleanup needed. */
52
+ [data-framer-appear-id]${WIDGET_SEL} {
53
+ opacity: 1 !important;
54
+ transform: none !important;
55
+ }
56
+
57
+ /* --- Force any inline-hidden elements visible ---
58
+ * Some animation frameworks (AOS, wow.js, Framer scroll) hide
59
+ * elements via inline opacity:0 or visibility:hidden. */
60
+ [style*="opacity: 0"]${WIDGET_SEL},
61
+ [style*="opacity:0"]${WIDGET_SEL} {
62
+ opacity: 1 !important;
63
+ }
64
+ [style*="visibility: hidden"]${WIDGET_SEL},
65
+ [style*="visibility:hidden"]${WIDGET_SEL} {
66
+ visibility: visible !important;
67
+ }
68
+
69
+ /* --- Neutralize interaction transforms --- */
70
+ *${WIDGET_SEL}:hover,
71
+ *${WIDGET_SEL}:focus,
72
+ *${WIDGET_SEL}:focus-within,
73
+ *${WIDGET_SEL}:focus-visible,
74
+ *${WIDGET_SEL}:active {
125
75
  transform: none !important;
126
76
  scale: 1 !important;
127
77
  rotate: 0deg !important;
@@ -139,35 +89,58 @@ function createAnimationStopModule() {
139
89
  try {
140
90
  const target = anim.effect?.target;
141
91
  if (!target) return false;
142
- let node = target;
143
- while (node) {
144
- if (node.id === "accessify-root") return true;
145
- const parent = node.parentNode || node.host;
146
- if (parent === node) break;
147
- node = parent;
148
- }
92
+ return isWidgetElement(target);
149
93
  } catch {
150
94
  }
151
95
  return false;
152
96
  }
153
- function finishAllAnimations() {
97
+ function cancelAllAnimations() {
154
98
  try {
155
99
  const animations = document.getAnimations?.();
156
100
  if (!animations) return;
157
101
  for (const anim of animations) {
158
102
  if (isWidgetAnimation(anim)) continue;
159
103
  try {
160
- anim.finish();
104
+ anim.cancel();
161
105
  } catch {
162
- try {
163
- anim.cancel();
164
- } catch {
165
- }
166
106
  }
167
107
  }
168
108
  } catch {
169
109
  }
170
110
  }
111
+ function patchAnimate() {
112
+ if (originalAnimate) return;
113
+ originalAnimate = Element.prototype.animate;
114
+ Element.prototype.animate = function(keyframes, options) {
115
+ if (!enabled) {
116
+ return originalAnimate.call(this, keyframes, options);
117
+ }
118
+ if (isWidgetElement(this)) {
119
+ return originalAnimate.call(this, keyframes, options);
120
+ }
121
+ const opts = typeof options === "number" ? { duration: 1e-3, fill: "none" } : {
122
+ ...options || {},
123
+ duration: 1e-3,
124
+ delay: 0,
125
+ iterations: 1,
126
+ fill: "none"
127
+ };
128
+ delete opts.iterationStart;
129
+ delete opts.endDelay;
130
+ const anim = originalAnimate.call(this, keyframes, opts);
131
+ try {
132
+ anim.cancel();
133
+ } catch {
134
+ }
135
+ return anim;
136
+ };
137
+ }
138
+ function restoreAnimate() {
139
+ if (originalAnimate) {
140
+ Element.prototype.animate = originalAnimate;
141
+ originalAnimate = null;
142
+ }
143
+ }
171
144
  function patchGSAP() {
172
145
  const g = window.gsap;
173
146
  if (g?.globalTimeline) {
@@ -188,111 +161,11 @@ function createAnimationStopModule() {
188
161
  }
189
162
  }
190
163
  }
191
- function forceHiddenElementsVisible() {
192
- const viewH = window.innerHeight;
193
- const margin = viewH * 1.5;
194
- const all = document.querySelectorAll("*");
195
- for (const el of all) {
196
- if (el.tagName === "SCRIPT" || el.tagName === "STYLE" || el.tagName === "NOSCRIPT" || el.tagName === "META" || el.tagName === "LINK") continue;
197
- if (el.closest("#accessify-root") || el.closest("accessify-widget")) continue;
198
- if (el.dataset.a11yOrigStyle) continue;
199
- const computed = window.getComputedStyle(el);
200
- if (computed.display === "none") continue;
201
- const rect = el.getBoundingClientRect();
202
- if (rect.top > viewH + margin) continue;
203
- if (rect.bottom < -margin) continue;
204
- const inline = el.style;
205
- let needsFix = false;
206
- const originals = {};
207
- const opacityVal = parseFloat(computed.opacity);
208
- if (opacityVal < 0.1 && inline.opacity !== "") {
209
- originals.opacity = inline.opacity;
210
- el.style.opacity = "1";
211
- needsFix = true;
212
- } else if (opacityVal < 0.1 && el.hasAttribute("data-framer-appear-id")) {
213
- originals.opacity = inline.opacity || "";
214
- el.style.opacity = "1";
215
- needsFix = true;
216
- }
217
- if (inline.transform && /translate[XY]\([^0]/.test(inline.transform)) {
218
- originals.transform = inline.transform;
219
- el.style.transform = "none";
220
- needsFix = true;
221
- }
222
- if (inline.visibility === "hidden") {
223
- originals.visibility = inline.visibility;
224
- el.style.visibility = "visible";
225
- needsFix = true;
226
- }
227
- if (inline.clipPath && inline.clipPath !== "none") {
228
- originals.clipPath = inline.clipPath;
229
- el.style.clipPath = "none";
230
- needsFix = true;
231
- }
232
- if (needsFix) {
233
- el.dataset.a11yOrigStyle = JSON.stringify(originals);
234
- }
235
- }
236
- }
237
- function restoreHiddenElements() {
238
- document.querySelectorAll("[data-a11y-orig-style]").forEach((el) => {
239
- try {
240
- const orig = JSON.parse(el.dataset.a11yOrigStyle || "{}");
241
- for (const [prop, val] of Object.entries(orig)) {
242
- if (val === "") {
243
- el.style.removeProperty(prop);
244
- } else {
245
- el.style[prop] = val;
246
- }
247
- }
248
- } catch {
249
- }
250
- delete el.dataset.a11yOrigStyle;
251
- });
252
- }
253
- function freezeScrollAnimations() {
254
- document.querySelectorAll("[style]").forEach((el) => {
255
- if (el.closest("#accessify-root") || el.closest("accessify-widget")) return;
256
- if (el.dataset.a11yFrozenStyle) return;
257
- const s = el.style;
258
- if (s.transform || s.opacity) {
259
- el.dataset.a11yFrozenStyle = JSON.stringify({
260
- transform: s.transform || "",
261
- opacity: s.opacity || ""
262
- });
263
- }
264
- });
265
- if (!scrollHandler) {
266
- scrollHandler = () => {
267
- if (!enabled) return;
268
- document.querySelectorAll("[data-a11y-frozen-style]").forEach((el) => {
269
- try {
270
- const frozen = JSON.parse(el.dataset.a11yFrozenStyle || "{}");
271
- if (frozen.transform && el.style.transform !== frozen.transform) {
272
- el.style.transform = frozen.transform;
273
- }
274
- } catch {
275
- }
276
- });
277
- };
278
- window.addEventListener("scroll", scrollHandler, { passive: true, capture: true });
279
- }
280
- }
281
- function unfreezeScrollAnimations() {
282
- if (scrollHandler) {
283
- window.removeEventListener("scroll", scrollHandler, true);
284
- scrollHandler = null;
285
- }
286
- document.querySelectorAll("[data-a11y-frozen-style]").forEach((el) => {
287
- delete el.dataset.a11yFrozenStyle;
288
- });
289
- }
290
164
  function pauseAllVideos() {
291
165
  document.querySelectorAll("video").forEach((v) => {
292
166
  if (!v.paused) {
293
167
  v.dataset.a11yPaused = "true";
294
168
  v.pause();
295
- pausedVideos.push(v);
296
169
  }
297
170
  });
298
171
  }
@@ -319,7 +192,6 @@ function createAnimationStopModule() {
319
192
  }
320
193
  delete v.dataset.a11yPaused;
321
194
  });
322
- pausedVideos = [];
323
195
  }
324
196
  function freezeGif(img) {
325
197
  const src = (img.currentSrc || img.src || "").toLowerCase();
@@ -388,6 +260,16 @@ function createAnimationStopModule() {
388
260
  }
389
261
  });
390
262
  }
263
+ function debouncedRescan() {
264
+ if (debounceTimer) clearTimeout(debounceTimer);
265
+ debounceTimer = setTimeout(() => {
266
+ if (!enabled) return;
267
+ cancelAllAnimations();
268
+ pauseAllVideos();
269
+ freezeAllGifs();
270
+ pauseSVG();
271
+ }, 150);
272
+ }
391
273
  function setupObserver() {
392
274
  if (mutationObserver) return;
393
275
  mutationObserver = new MutationObserver((mutations) => {
@@ -400,11 +282,7 @@ function createAnimationStopModule() {
400
282
  }
401
283
  }
402
284
  if (hasNewContent) {
403
- finishAllAnimations();
404
- forceHiddenElementsVisible();
405
- pauseAllVideos();
406
- freezeAllGifs();
407
- pauseSVG();
285
+ debouncedRescan();
408
286
  }
409
287
  });
410
288
  mutationObserver.observe(document.body, { childList: true, subtree: true });
@@ -412,13 +290,17 @@ function createAnimationStopModule() {
412
290
  function teardownObserver() {
413
291
  mutationObserver?.disconnect();
414
292
  mutationObserver = null;
293
+ if (debounceTimer) {
294
+ clearTimeout(debounceTimer);
295
+ debounceTimer = null;
296
+ }
415
297
  }
416
298
  function startPeriodicScan() {
417
299
  if (scanInterval) return;
418
300
  scanInterval = setInterval(() => {
419
301
  if (!enabled) return;
420
- finishAllAnimations();
421
- }, 500);
302
+ cancelAllAnimations();
303
+ }, 2e3);
422
304
  }
423
305
  function stopPeriodicScan() {
424
306
  if (scanInterval) {
@@ -431,10 +313,8 @@ function createAnimationStopModule() {
431
313
  enabled = true;
432
314
  patchAnimate();
433
315
  injectStyles();
434
- finishAllAnimations();
316
+ cancelAllAnimations();
435
317
  patchGSAP();
436
- forceHiddenElementsVisible();
437
- freezeScrollAnimations();
438
318
  pauseAllVideos();
439
319
  interceptVideoPlay();
440
320
  freezeAllGifs();
@@ -442,26 +322,29 @@ function createAnimationStopModule() {
442
322
  stopMarquees();
443
323
  setupObserver();
444
324
  startPeriodicScan();
445
- for (const delay of [50, 200, 500, 1e3, 2e3, 4e3]) {
446
- setTimeout(() => {
447
- if (!enabled) return;
448
- finishAllAnimations();
449
- forceHiddenElementsVisible();
450
- freezeScrollAnimations();
451
- pauseAllVideos();
452
- freezeAllGifs();
453
- }, delay);
454
- }
325
+ const schedule = (fn, ms) => setTimeout(() => {
326
+ if (enabled) fn();
327
+ }, ms);
328
+ delayedTimers.push(schedule(() => {
329
+ cancelAllAnimations();
330
+ pauseAllVideos();
331
+ freezeAllGifs();
332
+ }, 500));
333
+ delayedTimers.push(schedule(() => {
334
+ cancelAllAnimations();
335
+ pauseAllVideos();
336
+ freezeAllGifs();
337
+ }, 2e3));
455
338
  localStorage.setItem(STORAGE_KEY, "true");
456
339
  }
457
340
  function deactivate() {
458
341
  enabled = false;
342
+ for (const t of delayedTimers) clearTimeout(t);
343
+ delayedTimers = [];
459
344
  stopPeriodicScan();
460
345
  teardownObserver();
461
346
  restoreAnimate();
462
- unfreezeScrollAnimations();
463
347
  restoreGSAP();
464
- restoreHiddenElements();
465
348
  startMarquees();
466
349
  resumeSVG();
467
350
  restoreAllGifs();
@@ -487,4 +370,4 @@ function createAnimationStopModule() {
487
370
  export {
488
371
  createAnimationStopModule as default
489
372
  };
490
- //# sourceMappingURL=animation-stop-DrDe9Q9n.js.map
373
+ //# sourceMappingURL=animation-stop-_C-YdTs3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation-stop-_C-YdTs3.js","sources":["../src/features/animation-stop.ts"],"sourcesContent":["import type { FeatureModule, FeatureState } from '../types';\n\n/**\n * Animation Stop – V6 (Framer-Safe Rewrite)\n *\n * Layer 1: CSS injection — kill all CSS animations/transitions + force\n * Framer/WAAPI-hidden elements visible via CSS !important (no\n * inline-style manipulation that frameworks fight against).\n * Layer 2: Web Animations API — cancel all running WAAPI animations\n * Layer 3: Element.prototype.animate() intercept — kill new animations\n * Layer 4: GSAP globalTimeline freeze\n * Layer 5: Media — pause videos, freeze GIFs, stop SVG SMIL, marquees\n *\n * + MutationObserver for dynamic content (debounced)\n * + Periodic re-scan (every 2s) for frameworks that create new animations\n *\n * V6 key change: NO inline-style manipulation for visibility forcing.\n * Framer (and similar React-based frameworks) continuously re-set inline\n * styles via WAAPI and React renders. Overwriting inline styles creates an\n * infinite fight (our override → Framer re-sets → MutationObserver fires →\n * we override again → flicker). Instead, V6 uses CSS `!important` rules\n * in the injected stylesheet, which beat inline styles without triggering\n * a mutation loop.\n */\nexport default function createAnimationStopModule(): FeatureModule {\n let enabled = false;\n const STYLE_ID = 'a11y-stop-animations';\n const STORAGE_KEY = 'accessify-animation-stop';\n\n // --- State ---\n let mutationObserver: MutationObserver | null = null;\n let scanInterval: ReturnType<typeof setInterval> | null = null;\n let originalVideoPlay: typeof HTMLVideoElement.prototype.play | null = null;\n let originalAnimate: typeof Element.prototype.animate | null = null;\n let gifOriginals = new Map<HTMLImageElement, string>();\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n let delayedTimers: ReturnType<typeof setTimeout>[] = [];\n\n // =========================================================================\n // Helpers\n // =========================================================================\n\n const WIDGET_SEL = ':not(#accessify-root):not(#accessify-root *)';\n\n function isWidgetElement(el: Element | Node | null): boolean {\n try {\n let node: Node | null = el;\n while (node) {\n if ((node as Element).id === 'accessify-root') return true;\n const parent: Node | null =\n (node as Node).parentNode ||\n ((node as unknown as ShadowRoot).host as Node | null) ||\n null;\n if (parent === node) break;\n node = parent;\n }\n } catch { /* ignore */ }\n return false;\n }\n\n // =========================================================================\n // Layer 1: CSS Injection\n //\n // One big stylesheet handles EVERYTHING CSS can do:\n // a) Kill all transitions + CSS animations (0.001ms)\n // b) Force Framer-appear elements visible (opacity, transform)\n // c) Neutralize hover/focus transforms\n //\n // Because CSS !important beats inline styles, Framer can re-set its\n // inline opacity:0.001 as much as it wants — our rule wins. No JS\n // inline-style manipulation needed, no MutationObserver feedback loop.\n // =========================================================================\n\n function injectStyles() {\n if (document.getElementById(STYLE_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ID;\n style.textContent = `\n /* --- Kill all CSS-driven animations & transitions --- */\n *${WIDGET_SEL},\n *${WIDGET_SEL}::before,\n *${WIDGET_SEL}::after {\n animation-duration: 0.001ms !important;\n animation-iteration-count: 1 !important;\n animation-delay: 0s !important;\n animation-fill-mode: forwards !important;\n transition-duration: 0.001ms !important;\n transition-delay: 0s !important;\n scroll-behavior: auto !important;\n animation-timeline: auto !important;\n scroll-timeline: none !important;\n }\n\n /* --- Force Framer appear-elements visible --- *\n * Framer sets inline opacity:0.001 + transform:translateY(...)\n * on elements waiting for scroll/appear animations. We override\n * with !important which beats inline styles. When animation-stop\n * is deactivated, removing this stylesheet instantly restores\n * Framer's inline values — no cleanup needed. */\n [data-framer-appear-id]${WIDGET_SEL} {\n opacity: 1 !important;\n transform: none !important;\n }\n\n /* --- Force any inline-hidden elements visible ---\n * Some animation frameworks (AOS, wow.js, Framer scroll) hide\n * elements via inline opacity:0 or visibility:hidden. */\n [style*=\"opacity: 0\"]${WIDGET_SEL},\n [style*=\"opacity:0\"]${WIDGET_SEL} {\n opacity: 1 !important;\n }\n [style*=\"visibility: hidden\"]${WIDGET_SEL},\n [style*=\"visibility:hidden\"]${WIDGET_SEL} {\n visibility: visible !important;\n }\n\n /* --- Neutralize interaction transforms --- */\n *${WIDGET_SEL}:hover,\n *${WIDGET_SEL}:focus,\n *${WIDGET_SEL}:focus-within,\n *${WIDGET_SEL}:focus-visible,\n *${WIDGET_SEL}:active {\n transform: none !important;\n scale: 1 !important;\n rotate: 0deg !important;\n translate: 0 0 !important;\n filter: none !important;\n -webkit-filter: none !important;\n }\n `;\n document.head.appendChild(style);\n }\n\n function removeStyles() {\n document.getElementById(STYLE_ID)?.remove();\n }\n\n // =========================================================================\n // Layer 2: Web Animations API — cancel all WAAPI animations\n //\n // We cancel() instead of finish() to avoid leaving elements stuck in\n // animation end-states (e.g. scale(1.05) from a hover animation).\n // The CSS !important rules in Layer 1 handle visibility.\n // =========================================================================\n\n function isWidgetAnimation(anim: Animation): boolean {\n try {\n const target = (anim.effect as any)?.target as Element | null;\n if (!target) return false;\n return isWidgetElement(target);\n } catch { /* ignore */ }\n return false;\n }\n\n function cancelAllAnimations() {\n try {\n const animations = document.getAnimations?.();\n if (!animations) return;\n for (const anim of animations) {\n if (isWidgetAnimation(anim)) continue;\n try { anim.cancel(); } catch { /* ignore */ }\n }\n } catch { /* getAnimations not supported */ }\n }\n\n // =========================================================================\n // Layer 3: Element.prototype.animate() intercept\n //\n // Framer Motion creates new WAAPI animations constantly (hover, appear,\n // scroll). We intercept at creation time and cancel immediately.\n // =========================================================================\n\n function patchAnimate() {\n if (originalAnimate) return;\n originalAnimate = Element.prototype.animate;\n\n Element.prototype.animate = function (\n this: Element,\n keyframes: Keyframe[] | PropertyIndexedKeyframes | null,\n options?: number | KeyframeAnimationOptions,\n ): Animation {\n if (!enabled) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Never interfere with the widget's own animations.\n if (isWidgetElement(this)) {\n return originalAnimate!.call(this, keyframes, options);\n }\n\n // Create the animation with instant duration, then cancel it.\n // We must call originalAnimate (not skip it) because some frameworks\n // store the returned Animation object and call methods on it.\n const opts: KeyframeAnimationOptions = typeof options === 'number'\n ? { duration: 0.001, fill: 'none' as FillMode }\n : {\n ...(options || {}),\n duration: 0.001,\n delay: 0,\n iterations: 1,\n fill: 'none' as FillMode,\n };\n delete (opts as any).iterationStart;\n delete (opts as any).endDelay;\n\n const anim = originalAnimate!.call(this, keyframes, opts);\n try { anim.cancel(); } catch { /* ignore */ }\n return anim;\n };\n }\n\n function restoreAnimate() {\n if (originalAnimate) {\n Element.prototype.animate = originalAnimate;\n originalAnimate = null;\n }\n }\n\n // =========================================================================\n // Layer 4: GSAP\n // =========================================================================\n\n function patchGSAP() {\n const g = (window as any).gsap;\n if (g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(0);\n (window as any)._a11yGsapPatched = true;\n } catch { /* ignore */ }\n }\n }\n\n function restoreGSAP() {\n const g = (window as any).gsap;\n if ((window as any)._a11yGsapPatched && g?.globalTimeline) {\n try {\n g.globalTimeline.timeScale(1);\n delete (window as any)._a11yGsapPatched;\n } catch { /* ignore */ }\n }\n }\n\n // =========================================================================\n // Layer 5: Media\n // =========================================================================\n\n function pauseAllVideos() {\n document.querySelectorAll<HTMLVideoElement>('video').forEach(v => {\n if (!v.paused) {\n v.dataset.a11yPaused = 'true';\n v.pause();\n }\n });\n }\n\n function interceptVideoPlay() {\n if (originalVideoPlay) return;\n originalVideoPlay = HTMLVideoElement.prototype.play;\n HTMLVideoElement.prototype.play = function () {\n if (enabled) return Promise.resolve();\n return originalVideoPlay!.call(this);\n };\n }\n\n function restoreVideoPlay() {\n if (originalVideoPlay) {\n HTMLVideoElement.prototype.play = originalVideoPlay;\n originalVideoPlay = null;\n }\n }\n\n function resumeAllVideos() {\n restoreVideoPlay();\n document.querySelectorAll<HTMLVideoElement>('video[data-a11y-paused]').forEach(v => {\n try { v.play(); } catch { /* gone */ }\n delete v.dataset.a11yPaused;\n });\n }\n\n function freezeGif(img: HTMLImageElement) {\n const src = (img.currentSrc || img.src || '').toLowerCase();\n if (!src.match(/\\.gif(\\?|$)/i)) return;\n if (gifOriginals.has(img)) return;\n\n const doFreeze = () => {\n try {\n const w = img.naturalWidth || img.width;\n const h = img.naturalHeight || img.height;\n if (w === 0 || h === 0) return;\n const c = document.createElement('canvas');\n c.width = w; c.height = h;\n const ctx = c.getContext('2d');\n if (!ctx) return;\n ctx.drawImage(img, 0, 0);\n gifOriginals.set(img, img.src);\n img.src = c.toDataURL('image/png');\n } catch { /* CORS */ }\n };\n\n if (img.complete && img.naturalWidth > 0) doFreeze();\n else img.addEventListener('load', doFreeze, { once: true });\n }\n\n function freezeAllGifs() {\n document.querySelectorAll<HTMLImageElement>('img').forEach(freezeGif);\n }\n\n function restoreAllGifs() {\n for (const [img, src] of gifOriginals) {\n try { img.src = src; } catch { /* gone */ }\n }\n gifOriginals.clear();\n }\n\n function pauseSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).pauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function resumeSVG() {\n document.querySelectorAll('svg').forEach(s => {\n try { (s as any).unpauseAnimations?.(); } catch { /* ignore */ }\n });\n }\n\n function stopMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).stop?.(); } catch { /* ignore */ }\n });\n }\n\n function startMarquees() {\n document.querySelectorAll('marquee').forEach(m => {\n try { (m as any).start?.(); } catch { /* ignore */ }\n });\n }\n\n // =========================================================================\n // MutationObserver — dynamic content (debounced)\n //\n // V6: Only cancels WAAPI animations and pauses new media. Does NOT\n // manipulate inline styles (that's handled purely by CSS !important).\n // =========================================================================\n\n function debouncedRescan() {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n if (!enabled) return;\n cancelAllAnimations();\n pauseAllVideos();\n freezeAllGifs();\n pauseSVG();\n }, 150);\n }\n\n function setupObserver() {\n if (mutationObserver) return;\n mutationObserver = new MutationObserver(mutations => {\n if (!enabled) return;\n let hasNewContent = false;\n for (const m of mutations) {\n if (m.addedNodes.length > 0) { hasNewContent = true; break; }\n }\n if (hasNewContent) {\n debouncedRescan();\n }\n });\n mutationObserver.observe(document.body, { childList: true, subtree: true });\n }\n\n function teardownObserver() {\n mutationObserver?.disconnect();\n mutationObserver = null;\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n debounceTimer = null;\n }\n }\n\n // =========================================================================\n // Periodic re-scan — cancel animations frameworks keep creating\n // =========================================================================\n\n function startPeriodicScan() {\n if (scanInterval) return;\n scanInterval = setInterval(() => {\n if (!enabled) return;\n cancelAllAnimations();\n }, 2000);\n }\n\n function stopPeriodicScan() {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n }\n\n // =========================================================================\n // Lifecycle\n // =========================================================================\n\n function activate() {\n if (enabled) return;\n enabled = true;\n\n // Layer 3 first: intercept new WAAPI animations before anything else\n patchAnimate();\n\n // Layer 1: CSS — handles transitions, animations, AND visibility forcing\n injectStyles();\n\n // Layer 2: Cancel all currently running WAAPI animations\n cancelAllAnimations();\n\n // Layer 4: GSAP\n patchGSAP();\n\n // Layer 5: Media\n pauseAllVideos();\n interceptVideoPlay();\n freezeAllGifs();\n pauseSVG();\n stopMarquees();\n\n // Observers\n setupObserver();\n startPeriodicScan();\n\n // Two delayed re-scans for late-loading frameworks (reduced from 6).\n const schedule = (fn: () => void, ms: number) =>\n setTimeout(() => { if (enabled) fn(); }, ms);\n\n delayedTimers.push(schedule(() => {\n cancelAllAnimations();\n pauseAllVideos();\n freezeAllGifs();\n }, 500));\n\n delayedTimers.push(schedule(() => {\n cancelAllAnimations();\n pauseAllVideos();\n freezeAllGifs();\n }, 2000));\n\n localStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function deactivate() {\n enabled = false;\n\n // Clear all timers\n for (const t of delayedTimers) clearTimeout(t);\n delayedTimers = [];\n\n stopPeriodicScan();\n teardownObserver();\n restoreAnimate();\n restoreGSAP();\n startMarquees();\n resumeSVG();\n restoreAllGifs();\n resumeAllVideos();\n\n // Remove CSS — this instantly restores all visibility, transitions,\n // and animations because the !important rules are gone.\n removeStyles();\n\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'animation-stop',\n name: () => 'Stop Animations',\n description: 'Pause all animations, transitions, and auto-playing videos (WCAG 2.3.1)',\n icon: 'animation-stop',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'animation-stop', enabled }),\n setState: (state: { enabled: boolean }) => {\n if (state.enabled) activate();\n else deactivate();\n },\n };\n}\n"],"names":[],"mappings":"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"}
@@ -6620,6 +6620,8 @@ function FeatureGrid($$anchor, $$props) {
6620
6620
  }
6621
6621
  };
6622
6622
  const INLINE_CONTROLS = /* @__PURE__ */ new Set(["contrast", "text-size"]);
6623
+ const MOUSE_ONLY_FEATURES = /* @__PURE__ */ new Set(["big-cursor", "reading-guide", "reading-mask"]);
6624
+ const isTouchOnly = typeof window !== "undefined" && navigator.maxTouchPoints > 0 && window.matchMedia("(pointer:coarse)").matches && !window.matchMedia("(pointer:fine)").matches;
6623
6625
  const CONTRAST_MODES = [
6624
6626
  {
6625
6627
  id: "light",
@@ -6642,17 +6644,17 @@ function FeatureGrid($$anchor, $$props) {
6642
6644
  const FEATURE_LOADERS = {
6643
6645
  contrast: () => import("./contrast-CqsOs6Uo.js"),
6644
6646
  "text-size": () => import("./text-size-m_mHNPWo.js"),
6645
- "keyboard-nav": () => import("./keyboard-nav-BMIfQKyz.js"),
6647
+ "keyboard-nav": () => import("./keyboard-nav-Nik2sdpI.js"),
6646
6648
  "link-highlight": () => import("./link-highlight-D9gxFmiG.js"),
6647
6649
  "reading-guide": () => import("./reading-guide-C_jxzorm.js"),
6648
6650
  "reading-mask": () => import("./reading-mask-B_NxbhTN.js"),
6649
- "animation-stop": () => import("./animation-stop-DrDe9Q9n.js"),
6651
+ "animation-stop": () => import("./animation-stop-_C-YdTs3.js"),
6650
6652
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6651
6653
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6652
- "page-structure": () => import("./page-structure-BimA9vQz.js"),
6654
+ "page-structure": () => import("./page-structure-Bb8fqHoF.js"),
6653
6655
  tts: () => import("./tts-zrXtEd07.js"),
6654
6656
  "text-simplify": () => import("./text-simplify-BIFpqadq.js"),
6655
- "alt-text": () => import("./alt-text-CoS2ISqs.js")
6657
+ "alt-text": () => import("./alt-text-B0oky8BQ.js")
6656
6658
  };
6657
6659
  let contrastMode = /* @__PURE__ */ state(proxy(readStoredContrastMode()));
6658
6660
  let textSize = /* @__PURE__ */ state(proxy(readStoredTextSize()));
@@ -6786,7 +6788,7 @@ function FeatureGrid($$anchor, $$props) {
6786
6788
  $$props.ontoggle("text-size", true);
6787
6789
  $$props.ontextsize?.(value);
6788
6790
  }
6789
- let cardFeatures = /* @__PURE__ */ user_derived(() => $$props.config.features.filter((id) => !INLINE_CONTROLS.has(id) && FEATURE_REGISTRY[id]).map((id) => FEATURE_REGISTRY[id]));
6791
+ let cardFeatures = /* @__PURE__ */ user_derived(() => $$props.config.features.filter((id) => !INLINE_CONTROLS.has(id) && FEATURE_REGISTRY[id] && !(isTouchOnly && MOUSE_ONLY_FEATURES.has(id))).map((id) => FEATURE_REGISTRY[id]));
6790
6792
  user_effect(() => {
6791
6793
  `${$$props.config.features.join("|")}|${get(activeSignature)}`;
6792
6794
  void syncActiveModules();
@@ -8323,7 +8325,7 @@ async function init(userConfig = {}) {
8323
8325
  }
8324
8326
  });
8325
8327
  document.body.appendChild(containerEl);
8326
- import("./alt-text-CoS2ISqs.js").then((m) => m.autoApplyCachedAltTexts(config)).catch(() => {
8328
+ import("./alt-text-B0oky8BQ.js").then((m) => m.autoApplyCachedAltTexts(config)).catch(() => {
8327
8329
  });
8328
8330
  config.onReady?.();
8329
8331
  }
@@ -8366,4 +8368,4 @@ export {
8366
8368
  init as i,
8367
8369
  t
8368
8370
  };
8369
- //# sourceMappingURL=index-DCvvWewP.js.map
8371
+ //# sourceMappingURL=index-Dmhdz9kR.js.map