accessify-widget 0.2.1 → 0.2.3

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.
@@ -254,8 +254,6 @@ https://svelte.dev/e/svelte_boundary_reset_onerror`);
254
254
  }
255
255
  const EACH_ITEM_REACTIVE = 1;
256
256
  const EACH_INDEX_REACTIVE = 1 << 1;
257
- const EACH_IS_CONTROLLED = 1 << 2;
258
- const EACH_IS_ANIMATED = 1 << 3;
259
257
  const EACH_ITEM_IMMUTABLE = 1 << 4;
260
258
  const PROPS_IS_IMMUTABLE = 1;
261
259
  const PROPS_IS_UPDATED = 1 << 2;
@@ -279,15 +277,6 @@ https://svelte.dev/e/lifecycle_double_unmount`, bold, normal);
279
277
  console.warn(`https://svelte.dev/e/lifecycle_double_unmount`);
280
278
  }
281
279
  }
282
- function select_multiple_invalid_value() {
283
- if (DEV) {
284
- console.warn(`%c[svelte] select_multiple_invalid_value
285
- %cThe \`value\` property of a \`<select multiple>\` element should be an array, but it received a non-array value. The selection will be kept as is.
286
- https://svelte.dev/e/select_multiple_invalid_value`, bold, normal);
287
- } else {
288
- console.warn(`https://svelte.dev/e/select_multiple_invalid_value`);
289
- }
290
- }
291
280
  function state_proxy_equality_mismatch(operator) {
292
281
  if (DEV) {
293
282
  console.warn(`%c[svelte] state_proxy_equality_mismatch
@@ -2319,9 +2308,6 @@ function get_proxied_value(value) {
2319
2308
  }
2320
2309
  return value;
2321
2310
  }
2322
- function is(a, b) {
2323
- return Object.is(get_proxied_value(a), get_proxied_value(b));
2324
- }
2325
2311
  const ARRAY_MUTATING_METHODS = /* @__PURE__ */ new Set([
2326
2312
  "copyWithin",
2327
2313
  "fill",
@@ -2476,7 +2462,7 @@ function clear_text_content(node) {
2476
2462
  function should_defer_append() {
2477
2463
  return false;
2478
2464
  }
2479
- function create_element(tag2, namespace, is2) {
2465
+ function create_element(tag2, namespace, is) {
2480
2466
  let options = void 0;
2481
2467
  return (
2482
2468
  /** @type {T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : Element} */
@@ -3421,13 +3407,39 @@ function from_html(content, flags2) {
3421
3407
  return clone;
3422
3408
  };
3423
3409
  }
3424
- function comment() {
3425
- var frag = document.createDocumentFragment();
3426
- var start = document.createComment("");
3427
- var anchor = create_text();
3428
- frag.append(start, anchor);
3429
- assign_nodes(start, anchor);
3430
- return frag;
3410
+ // @__NO_SIDE_EFFECTS__
3411
+ function from_namespace(content, flags2, ns = "svg") {
3412
+ var has_start = !content.startsWith("<!>");
3413
+ var wrapped = `<${ns}>${has_start ? content : "<!>" + content}</${ns}>`;
3414
+ var node;
3415
+ return () => {
3416
+ if (!node) {
3417
+ var fragment = (
3418
+ /** @type {DocumentFragment} */
3419
+ create_fragment_from_html(wrapped)
3420
+ );
3421
+ var root2 = (
3422
+ /** @type {Element} */
3423
+ /* @__PURE__ */ get_first_child(fragment)
3424
+ );
3425
+ {
3426
+ node = /** @type {Element} */
3427
+ /* @__PURE__ */ get_first_child(root2);
3428
+ }
3429
+ }
3430
+ var clone = (
3431
+ /** @type {TemplateNode} */
3432
+ node.cloneNode(true)
3433
+ );
3434
+ {
3435
+ assign_nodes(clone, clone);
3436
+ }
3437
+ return clone;
3438
+ };
3439
+ }
3440
+ // @__NO_SIDE_EFFECTS__
3441
+ function from_svg(content, flags2) {
3442
+ return /* @__PURE__ */ from_namespace(content, flags2, "svg");
3431
3443
  }
3432
3444
  function append(anchor, dom) {
3433
3445
  if (anchor === null) {
@@ -3822,8 +3834,7 @@ var offscreen_anchor;
3822
3834
  function each(node, flags2, get_collection, get_key, render_fn2, fallback_fn = null) {
3823
3835
  var anchor = node;
3824
3836
  var items = /* @__PURE__ */ new Map();
3825
- var is_controlled = (flags2 & EACH_IS_CONTROLLED) !== 0;
3826
- if (is_controlled) {
3837
+ {
3827
3838
  var parent_node = (
3828
3839
  /** @type {Element} */
3829
3840
  node
@@ -3948,31 +3959,17 @@ function skip_to_branch(effect2) {
3948
3959
  return effect2;
3949
3960
  }
3950
3961
  function reconcile(state2, array, anchor, flags2, get_key) {
3951
- var is_animated = (flags2 & EACH_IS_ANIMATED) !== 0;
3952
3962
  var length = array.length;
3953
3963
  var items = state2.items;
3954
3964
  var current = skip_to_branch(state2.effect.first);
3955
3965
  var seen;
3956
3966
  var prev = null;
3957
- var to_animate;
3958
3967
  var matched = [];
3959
3968
  var stashed = [];
3960
3969
  var value;
3961
3970
  var key;
3962
3971
  var effect2;
3963
3972
  var i;
3964
- if (is_animated) {
3965
- for (i = 0; i < length; i += 1) {
3966
- value = array[i];
3967
- key = get_key(value, i);
3968
- effect2 = /** @type {EachItem} */
3969
- items.get(key).e;
3970
- if ((effect2.f & EFFECT_OFFSCREEN) === 0) {
3971
- effect2.nodes?.a?.measure();
3972
- (to_animate ?? (to_animate = /* @__PURE__ */ new Set())).add(effect2);
3973
- }
3974
- }
3975
- }
3976
3973
  for (i = 0; i < length; i += 1) {
3977
3974
  value = array[i];
3978
3975
  key = get_key(value, i);
@@ -4007,10 +4004,6 @@ function reconcile(state2, array, anchor, flags2, get_key) {
4007
4004
  }
4008
4005
  if ((effect2.f & INERT) !== 0) {
4009
4006
  resume_effect(effect2);
4010
- if (is_animated) {
4011
- effect2.nodes?.a?.unfix();
4012
- (to_animate ?? (to_animate = /* @__PURE__ */ new Set())).delete(effect2);
4013
- }
4014
4007
  }
4015
4008
  if (effect2 !== current) {
4016
4009
  if (seen !== void 0 && seen.has(effect2)) {
@@ -4089,26 +4082,10 @@ function reconcile(state2, array, anchor, flags2, get_key) {
4089
4082
  }
4090
4083
  var destroy_length = to_destroy.length;
4091
4084
  if (destroy_length > 0) {
4092
- var controlled_anchor = (flags2 & EACH_IS_CONTROLLED) !== 0 && length === 0 ? anchor : null;
4093
- if (is_animated) {
4094
- for (i = 0; i < destroy_length; i += 1) {
4095
- to_destroy[i].nodes?.a?.measure();
4096
- }
4097
- for (i = 0; i < destroy_length; i += 1) {
4098
- to_destroy[i].nodes?.a?.fix();
4099
- }
4100
- }
4085
+ var controlled_anchor = length === 0 ? anchor : null;
4101
4086
  pause_effects(state2, to_destroy, controlled_anchor);
4102
4087
  }
4103
4088
  }
4104
- if (is_animated) {
4105
- queue_micro_task(() => {
4106
- if (to_animate === void 0) return;
4107
- for (effect2 of to_animate) {
4108
- effect2.nodes?.a?.apply();
4109
- }
4110
- });
4111
- }
4112
4089
  }
4113
4090
  function create_item(items, anchor, value, key, index2, render_fn2, flags2, get_collection) {
4114
4091
  var v = (flags2 & EACH_ITEM_REACTIVE) !== 0 ? (flags2 & EACH_ITEM_IMMUTABLE) === 0 ? /* @__PURE__ */ mutable_source(value, false, false) : source(value) : null;
@@ -4245,74 +4222,52 @@ function html(node, get_value, is_controlled = false, svg = false, mathml = fals
4245
4222
  }
4246
4223
  });
4247
4224
  }
4225
+ const whitespace = [..." \n\r\f \v\uFEFF"];
4248
4226
  function to_class(value, hash, directives) {
4249
4227
  var classname = value == null ? "" : "" + value;
4228
+ if (directives) {
4229
+ for (var key of Object.keys(directives)) {
4230
+ if (directives[key]) {
4231
+ classname = classname ? classname + " " + key : key;
4232
+ } else if (classname.length) {
4233
+ var len = key.length;
4234
+ var a = 0;
4235
+ while ((a = classname.indexOf(key, a)) >= 0) {
4236
+ var b = a + len;
4237
+ if ((a === 0 || whitespace.includes(classname[a - 1])) && (b === classname.length || whitespace.includes(classname[b]))) {
4238
+ classname = (a === 0 ? "" : classname.substring(0, a)) + classname.substring(b + 1);
4239
+ } else {
4240
+ a = b;
4241
+ }
4242
+ }
4243
+ }
4244
+ }
4245
+ }
4250
4246
  return classname === "" ? null : classname;
4251
4247
  }
4252
4248
  function set_class(dom, is_html, value, hash, prev_classes, next_classes) {
4253
4249
  var prev = dom.__className;
4254
4250
  if (prev !== value || prev === void 0) {
4255
- var next_class_name = to_class(value);
4251
+ var next_class_name = to_class(value, hash, next_classes);
4256
4252
  {
4257
4253
  if (next_class_name == null) {
4258
4254
  dom.removeAttribute("class");
4259
- } else {
4255
+ } else if (is_html) {
4260
4256
  dom.className = next_class_name;
4257
+ } else {
4258
+ dom.setAttribute("class", next_class_name);
4261
4259
  }
4262
4260
  }
4263
4261
  dom.__className = value;
4264
- }
4265
- return next_classes;
4266
- }
4267
- function select_option(select, value, mounting = false) {
4268
- if (select.multiple) {
4269
- if (value == void 0) {
4270
- return;
4271
- }
4272
- if (!is_array(value)) {
4273
- return select_multiple_invalid_value();
4274
- }
4275
- for (var option of select.options) {
4276
- option.selected = value.includes(get_option_value(option));
4277
- }
4278
- return;
4279
- }
4280
- for (option of select.options) {
4281
- var option_value = get_option_value(option);
4282
- if (is(option_value, value)) {
4283
- option.selected = true;
4284
- return;
4262
+ } else if (next_classes && prev_classes !== next_classes) {
4263
+ for (var key in next_classes) {
4264
+ var is_present = !!next_classes[key];
4265
+ if (prev_classes == null || is_present !== !!prev_classes[key]) {
4266
+ dom.classList.toggle(key, is_present);
4267
+ }
4285
4268
  }
4286
4269
  }
4287
- if (!mounting || value !== void 0) {
4288
- select.selectedIndex = -1;
4289
- }
4290
- }
4291
- function init_select(select) {
4292
- var observer = new MutationObserver(() => {
4293
- select_option(select, select.__value);
4294
- });
4295
- observer.observe(select, {
4296
- // Listen to option element changes
4297
- childList: true,
4298
- subtree: true,
4299
- // because of <optgroup>
4300
- // Listen to option element value attribute changes
4301
- // (doesn't get notified of select value changes,
4302
- // because that property is not reflected as an attribute)
4303
- attributes: true,
4304
- attributeFilter: ["value"]
4305
- });
4306
- teardown(() => {
4307
- observer.disconnect();
4308
- });
4309
- }
4310
- function get_option_value(option) {
4311
- if ("__value" in option) {
4312
- return option.__value;
4313
- } else {
4314
- return option.value;
4315
- }
4270
+ return next_classes;
4316
4271
  }
4317
4272
  const IS_CUSTOM_ELEMENT = Symbol("is custom element");
4318
4273
  const IS_HTML = Symbol("is html");
@@ -4800,7 +4755,7 @@ const deJson = {
4800
4755
  "feature.linkHighlight": "Links hervorheben",
4801
4756
  "feature.linkHighlight.desc": "Alle Links sichtbar unterstreichen",
4802
4757
  "feature.keyboardNav": "Tastaturnavigation",
4803
- "feature.keyboardNav.desc": "Erweiterte Tastatursteuerung und Shortcuts",
4758
+ "feature.keyboardNav.desc": "Seite nur mit Tastatur bedienen: Direkt zum Inhalt springen, mit Alt+H durch Überschriften navigieren, Alt+L für Seitenbereiche, Alt+K zeigt alle Tastenkombinationen",
4804
4759
  "feature.tts": "Vorlesen",
4805
4760
  "feature.tts.desc": "Text per Klick vorlesen lassen",
4806
4761
  "feature.textSimplify": "Text vereinfachen",
@@ -4889,7 +4844,7 @@ const enJson = {
4889
4844
  "feature.linkHighlight": "Highlight Links",
4890
4845
  "feature.linkHighlight.desc": "Underline and highlight all links",
4891
4846
  "feature.keyboardNav": "Keyboard Nav",
4892
- "feature.keyboardNav.desc": "Enhanced keyboard controls and shortcuts",
4847
+ "feature.keyboardNav.desc": "Navigate the page using only your keyboard: Skip to main content, Alt+H to jump through headings, Alt+L for page sections, Alt+K shows all shortcuts",
4893
4848
  "feature.tts": "Read Aloud",
4894
4849
  "feature.tts.desc": "Click any text to hear it spoken",
4895
4850
  "feature.textSimplify": "Simplify Text",
@@ -4934,6 +4889,8 @@ const EN_BASE = {
4934
4889
  ...enJson,
4935
4890
  "widget.subtitle": "Adjust contrast, text and navigation on this page",
4936
4891
  "widget.language": "Language",
4892
+ "widget.widgetLang": "Widget language",
4893
+ "widget.moveWidget": "Move widget to other side",
4937
4894
  "widget.poweredBy": "Powered by Accessify-Widget",
4938
4895
  "section.essentials": "Most used",
4939
4896
  "section.essentials.desc": "Start with contrast, text size and keyboard support.",
@@ -4965,6 +4922,8 @@ const DE_BASE = {
4965
4922
  ...deJson,
4966
4923
  "widget.subtitle": "Passe Kontrast, Text und Navigation auf dieser Seite an",
4967
4924
  "widget.language": "Sprache",
4925
+ "widget.widgetLang": "Widget-Sprache",
4926
+ "widget.moveWidget": "Widget auf andere Seite verschieben",
4968
4927
  "widget.poweredBy": "Bereitgestellt von Accessify-Widget",
4969
4928
  "section.essentials": "Am haeufigsten genutzt",
4970
4929
  "section.essentials.desc": "Starte mit Kontrast, Textgroesse und Tastaturhilfe.",
@@ -4999,6 +4958,7 @@ const locales = {
4999
4958
  en: EN_BASE,
5000
4959
  de: DE_BASE,
5001
4960
  zh: withEnglish({
4961
+ "widget.widgetLang": "小组件语言",
5002
4962
  "widget.title": "无障碍",
5003
4963
  "widget.subtitle": "调整此页面的对比度、文字和导航",
5004
4964
  "widget.open": "打开无障碍设置",
@@ -5041,6 +5001,7 @@ const locales = {
5041
5001
  "feature.autoScan": "WCAG 扫描"
5042
5002
  }),
5043
5003
  hi: withEnglish({
5004
+ "widget.widgetLang": "विजेट भाषा",
5044
5005
  "widget.title": "सुलभता",
5045
5006
  "widget.subtitle": "इस पेज पर कंट्रास्ट, टेक्स्ट और नेविगेशन समायोजित करें",
5046
5007
  "widget.open": "सुलभता सेटिंग खोलें",
@@ -5083,6 +5044,7 @@ const locales = {
5083
5044
  "feature.autoScan": "WCAG स्कैन"
5084
5045
  }),
5085
5046
  es: withEnglish({
5047
+ "widget.widgetLang": "Idioma del widget",
5086
5048
  "widget.title": "Accesibilidad",
5087
5049
  "widget.subtitle": "Ajusta contraste, texto y navegacion en esta pagina",
5088
5050
  "widget.open": "Abrir ajustes de accesibilidad",
@@ -5125,6 +5087,7 @@ const locales = {
5125
5087
  "feature.autoScan": "Escaneo WCAG"
5126
5088
  }),
5127
5089
  fr: withEnglish({
5090
+ "widget.widgetLang": "Langue du widget",
5128
5091
  "widget.title": "Accessibilite",
5129
5092
  "widget.subtitle": "Ajustez le contraste, le texte et la navigation sur cette page",
5130
5093
  "widget.open": "Ouvrir les reglages d'accessibilite",
@@ -5167,6 +5130,7 @@ const locales = {
5167
5130
  "feature.autoScan": "Analyse WCAG"
5168
5131
  }),
5169
5132
  ar: withEnglish({
5133
+ "widget.widgetLang": "لغة الأداة",
5170
5134
  "widget.title": "إمكانية الوصول",
5171
5135
  "widget.subtitle": "اضبط التباين والنص والتنقل في هذه الصفحة",
5172
5136
  "widget.open": "افتح إعدادات إمكانية الوصول",
@@ -5251,6 +5215,7 @@ const locales = {
5251
5215
  "feature.autoScan": "WCAG স্ক্যান"
5252
5216
  }),
5253
5217
  pt: withEnglish({
5218
+ "widget.widgetLang": "Idioma do widget",
5254
5219
  "widget.title": "Acessibilidade",
5255
5220
  "widget.subtitle": "Ajuste contraste, texto e navegacao nesta pagina",
5256
5221
  "widget.open": "Abrir configuracoes de acessibilidade",
@@ -5293,6 +5258,7 @@ const locales = {
5293
5258
  "feature.autoScan": "Varredura WCAG"
5294
5259
  }),
5295
5260
  ru: withEnglish({
5261
+ "widget.widgetLang": "Язык виджета",
5296
5262
  "widget.title": "Доступность",
5297
5263
  "widget.subtitle": "Настройте контраст, текст и навигацию на этой странице",
5298
5264
  "widget.open": "Открыть настройки доступности",
@@ -5419,6 +5385,7 @@ const locales = {
5419
5385
  "feature.autoScan": "Pindai WCAG"
5420
5386
  }),
5421
5387
  ja: withEnglish({
5388
+ "widget.widgetLang": "ウィジェットの言語",
5422
5389
  "widget.title": "アクセシビリティ",
5423
5390
  "widget.subtitle": "このページのコントラスト、文字、ナビゲーションを調整します",
5424
5391
  "widget.open": "アクセシビリティ設定を開く",
@@ -5587,6 +5554,7 @@ const locales = {
5587
5554
  "feature.autoScan": "WCAG స్కాన్"
5588
5555
  }),
5589
5556
  tr: withEnglish({
5557
+ "widget.widgetLang": "Widget dili",
5590
5558
  "widget.title": "Erisilebilirlik",
5591
5559
  "widget.subtitle": "Bu sayfada kontrast, metin ve gezinmeyi ayarlayin",
5592
5560
  "widget.open": "Erisilebilirlik ayarlarini ac",
@@ -5713,6 +5681,7 @@ const locales = {
5713
5681
  "feature.autoScan": "Quet WCAG"
5714
5682
  }),
5715
5683
  ko: withEnglish({
5684
+ "widget.widgetLang": "위젯 언어",
5716
5685
  "widget.title": "접근성",
5717
5686
  "widget.subtitle": "이 페이지의 대비, 텍스트, 내비게이션을 조정하세요",
5718
5687
  "widget.open": "접근성 설정 열기",
@@ -5756,16 +5725,16 @@ const locales = {
5756
5725
  })
5757
5726
  };
5758
5727
  const LANGUAGE_OPTIONS = [
5759
- { code: "de", label: "Deutsch" },
5760
- { code: "en", label: "English" },
5761
- { code: "es", label: "Español" },
5762
- { code: "fr", label: "Français" },
5763
- { code: "pt", label: "Português" },
5764
- { code: "tr", label: "Türkçe" },
5765
- { code: "ar", label: "العربية" },
5766
- { code: "zh", label: "中文" },
5767
- { code: "ja", label: "日本語" },
5768
- { code: "ru", label: "Русский" }
5728
+ { code: "de", label: "Deutsch", flag: "🇩🇪" },
5729
+ { code: "en", label: "English", flag: "🇺🇸" },
5730
+ { code: "es", label: "Español", flag: "🇪🇸" },
5731
+ { code: "fr", label: "Français", flag: "🇫🇷" },
5732
+ { code: "pt", label: "Português", flag: "🇧🇷" },
5733
+ { code: "tr", label: "Türkçe", flag: "🇹🇷" },
5734
+ { code: "ar", label: "العربية", flag: "🇸🇦" },
5735
+ { code: "zh", label: "中文", flag: "🇨🇳" },
5736
+ { code: "ja", label: "日本語", flag: "🇯🇵" },
5737
+ { code: "ru", label: "Русский", flag: "🇷🇺" }
5769
5738
  ];
5770
5739
  const RTL_LANGS = /* @__PURE__ */ new Set(["ar", "ur"]);
5771
5740
  let currentWidgetLang = "en";
@@ -5789,15 +5758,75 @@ function t(key, lang = "en") {
5789
5758
  const resolved = getSupportedLang(lang);
5790
5759
  return locales[resolved]?.[key] || EN_BASE[key] || key;
5791
5760
  }
5792
- var root$5 = /* @__PURE__ */ from_html(`<button class="accessify-trigger"></button>`);
5761
+ var root$5 = /* @__PURE__ */ from_html(`<button></button>`);
5793
5762
  function TriggerButton($$anchor, $$props) {
5794
5763
  push($$props, true);
5795
5764
  let lang = prop($$props, "lang", 3, "en"), el = prop($$props, "el", 15, null);
5765
+ let isDragging = /* @__PURE__ */ state(false);
5766
+ onMount(() => {
5767
+ const btn = el();
5768
+ if (!btn) return;
5769
+ let dragStartX = 0;
5770
+ let dragStartY = 0;
5771
+ let startLeft = 0;
5772
+ let startTop = 0;
5773
+ let hasMoved = false;
5774
+ let pointerId = null;
5775
+ function onDown(e) {
5776
+ if ($$props.isOpen) return;
5777
+ const rect = btn.getBoundingClientRect();
5778
+ dragStartX = e.clientX;
5779
+ dragStartY = e.clientY;
5780
+ startLeft = rect.left;
5781
+ startTop = rect.top;
5782
+ hasMoved = false;
5783
+ pointerId = e.pointerId;
5784
+ btn.setPointerCapture(e.pointerId);
5785
+ }
5786
+ function onMove(e) {
5787
+ if (pointerId === null || e.pointerId !== pointerId) return;
5788
+ const dx = e.clientX - dragStartX;
5789
+ const dy = e.clientY - dragStartY;
5790
+ if (!hasMoved && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
5791
+ hasMoved = true;
5792
+ set(isDragging, true);
5793
+ btn.style.transition = "none";
5794
+ }
5795
+ if (hasMoved) {
5796
+ const newLeft = Math.max(0, Math.min(window.innerWidth - 60, startLeft + dx));
5797
+ const newTop = Math.max(0, Math.min(window.innerHeight - 60, startTop + dy));
5798
+ btn.style.left = newLeft + "px";
5799
+ btn.style.top = newTop + "px";
5800
+ btn.style.right = "auto";
5801
+ btn.style.bottom = "auto";
5802
+ }
5803
+ }
5804
+ function onUp(e) {
5805
+ if (pointerId === null || e.pointerId !== pointerId) return;
5806
+ btn.releasePointerCapture(e.pointerId);
5807
+ btn.style.transition = "";
5808
+ set(isDragging, false);
5809
+ if (!hasMoved) {
5810
+ $$props.onclick();
5811
+ }
5812
+ pointerId = null;
5813
+ }
5814
+ btn.addEventListener("pointerdown", onDown);
5815
+ btn.addEventListener("pointermove", onMove);
5816
+ btn.addEventListener("pointerup", onUp);
5817
+ return () => {
5818
+ btn.removeEventListener("pointerdown", onDown);
5819
+ btn.removeEventListener("pointermove", onMove);
5820
+ btn.removeEventListener("pointerup", onUp);
5821
+ };
5822
+ });
5796
5823
  var button = root$5();
5824
+ let classes;
5797
5825
  html(button, () => $$props.isOpen ? iconClose() : iconAccessibility(), true);
5798
5826
  bind_this(button, ($$value) => el($$value), () => el());
5799
5827
  template_effect(
5800
5828
  ($0) => {
5829
+ classes = set_class(button, 1, "accessify-trigger", null, classes, { "accessify-trigger--dragging": get(isDragging) });
5801
5830
  set_attribute(button, "aria-expanded", $$props.isOpen);
5802
5831
  set_attribute(button, "aria-label", $0);
5803
5832
  },
@@ -5805,134 +5834,160 @@ function TriggerButton($$anchor, $$props) {
5805
5834
  () => $$props.isOpen ? t("widget.close", lang()) : t("widget.open", lang())
5806
5835
  ]
5807
5836
  );
5808
- delegated("click", button, function(...$$args) {
5809
- $$props.onclick?.apply(this, $$args);
5810
- });
5811
5837
  append($$anchor, button);
5812
5838
  pop();
5813
5839
  }
5814
- delegate(["click"]);
5815
- var root_2$1 = /* @__PURE__ */ from_html(`<option> </option>`);
5816
- var root_1$3 = /* @__PURE__ */ from_html(`<label class="accessify-language-picker"><span class="sr-only"> </span> <span class="accessify-language-icon" aria-hidden="true"></span> <select class="accessify-language-select"></select></label>`);
5817
- var root$4 = /* @__PURE__ */ from_html(`<div class="accessify-header"><div class="accessify-header-top"><div class="accessify-header-title"><h2> </h2> <p> </p></div> <button class="accessify-header-btn accessify-header-btn--icon"></button></div> <div class="accessify-header-toolbar"><!> <button class="accessify-header-btn accessify-header-btn--secondary"><!> <span> </span></button></div></div>`);
5840
+ var root$4 = /* @__PURE__ */ from_html(`<header class="accessify-header"><div class="accessify-header-left"><span class="accessify-logo" aria-label="Accessify"><svg viewBox="0 0 480 80" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><text x="0" y="64" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="72" font-weight="700" letter-spacing="-2">accessify</text></svg></span></div> <div class="accessify-header-actions"><button class="accessify-header-btn"></button> <button class="accessify-header-btn accessify-header-btn--icon accessify-header-btn--close"></button></div></header>`);
5818
5841
  function PanelHeader($$anchor, $$props) {
5819
5842
  push($$props, true);
5820
5843
  let lang = prop($$props, "lang", 3, "en");
5821
- function handleLanguageChange(event2) {
5822
- const target = event2.currentTarget;
5823
- $$props.onlangchange?.(target.value);
5824
- }
5825
- var div = root$4();
5826
- var div_1 = child(div);
5827
- var div_2 = child(div_1);
5828
- var h2 = child(div_2);
5829
- var text = child(h2);
5830
- var p = sibling(h2, 2);
5831
- var text_1 = child(p);
5832
- var button = sibling(div_2, 2);
5833
- html(button, iconClose, true);
5834
- var div_3 = sibling(div_1, 2);
5835
- var node = child(div_3);
5836
- {
5837
- var consequent = ($$anchor2) => {
5838
- var label = root_1$3();
5839
- var span = child(label);
5840
- var text_2 = child(span);
5841
- var span_1 = sibling(span, 2);
5842
- html(span_1, iconGlobe, true);
5843
- var select = sibling(span_1, 2);
5844
- each(select, 21, () => LANGUAGE_OPTIONS, index, ($$anchor3, option) => {
5845
- var option_1 = root_2$1();
5846
- var text_3 = child(option_1);
5847
- var option_1_value = {};
5848
- template_effect(() => {
5849
- set_text(text_3, get(option).label);
5850
- if (option_1_value !== (option_1_value = get(option).code)) {
5851
- option_1.value = (option_1.__value = get(option).code) ?? "";
5852
- }
5853
- });
5854
- append($$anchor3, option_1);
5855
- });
5856
- var select_value;
5857
- init_select(select);
5858
- template_effect(
5859
- ($0, $1) => {
5860
- set_text(text_2, $0);
5861
- set_attribute(select, "aria-label", $1);
5862
- if (select_value !== (select_value = lang())) {
5863
- select.value = (select.__value = lang()) ?? "", select_option(select, lang());
5864
- }
5865
- },
5866
- [
5867
- () => t("widget.language", lang()),
5868
- () => t("widget.language", lang())
5869
- ]
5870
- );
5871
- delegated("change", select, handleLanguageChange);
5872
- append($$anchor2, label);
5873
- };
5874
- if_block(node, ($$render) => {
5875
- if ($$props.onlangchange) $$render(consequent);
5876
- });
5877
- }
5878
- var button_1 = sibling(node, 2);
5879
- var node_1 = child(button_1);
5880
- html(node_1, iconReset);
5881
- var span_2 = sibling(node_1, 2);
5882
- var text_4 = child(span_2);
5844
+ prop($$props, "activeCount", 3, 0);
5845
+ var header = root$4();
5846
+ var div = sibling(child(header), 2);
5847
+ var button = child(div);
5848
+ html(button, iconReset, true);
5849
+ var button_1 = sibling(button, 2);
5850
+ html(button_1, iconClose, true);
5883
5851
  template_effect(
5884
- ($0, $1, $2, $3, $4) => {
5885
- set_text(text, $0);
5886
- set_text(text_1, $1);
5887
- set_attribute(button, "aria-label", $2);
5888
- set_attribute(button_1, "aria-label", $3);
5889
- set_text(text_4, $4);
5852
+ ($0, $1) => {
5853
+ set_attribute(button, "aria-label", $0);
5854
+ set_attribute(button_1, "aria-label", $1);
5890
5855
  },
5891
5856
  [
5892
- () => t("widget.title", lang()),
5893
- () => t("widget.subtitle", lang()),
5894
- () => t("widget.close", lang()),
5895
5857
  () => t("widget.reset", lang()),
5896
- () => t("widget.reset", lang())
5858
+ () => t("widget.close", lang())
5897
5859
  ]
5898
5860
  );
5899
5861
  delegated("click", button, function(...$$args) {
5900
- $$props.onclose?.apply(this, $$args);
5862
+ $$props.onreset?.apply(this, $$args);
5901
5863
  });
5902
5864
  delegated("click", button_1, function(...$$args) {
5903
- $$props.onreset?.apply(this, $$args);
5865
+ $$props.onclose?.apply(this, $$args);
5904
5866
  });
5905
- append($$anchor, div);
5867
+ append($$anchor, header);
5906
5868
  pop();
5907
5869
  }
5908
- delegate(["click", "change"]);
5909
- var root_1$2 = /* @__PURE__ */ from_html(`<button class="accessify-status-reset"> </button>`);
5910
- var root$3 = /* @__PURE__ */ from_html(`<div class="accessify-status" role="status" aria-live="polite"><span class="accessify-status-count"> </span> <!></div>`);
5911
- function StatusBar($$anchor, $$props) {
5870
+ delegate(["click"]);
5871
+ const PROFILES = [
5872
+ {
5873
+ id: "vision-impaired",
5874
+ nameKey: "profile.visionImpaired",
5875
+ descKey: "profile.visionImpaired.desc",
5876
+ iconId: "eye",
5877
+ features: ["contrast", "text-size", "big-cursor", "link-highlight"],
5878
+ featureSettings: { "text-size": 150, contrast: "high" }
5879
+ },
5880
+ {
5881
+ id: "motor-impaired",
5882
+ nameKey: "profile.motorImpaired",
5883
+ descKey: "profile.motorImpaired.desc",
5884
+ iconId: "keyboard",
5885
+ features: ["keyboard-nav", "big-cursor", "link-highlight"]
5886
+ },
5887
+ {
5888
+ id: "cognitive",
5889
+ nameKey: "profile.cognitive",
5890
+ descKey: "profile.cognitive.desc",
5891
+ iconId: "brain",
5892
+ features: ["reading-guide", "text-size", "spacing", "dyslexia-font", "animation-stop"],
5893
+ featureSettings: { "text-size": 130 }
5894
+ },
5895
+ {
5896
+ id: "seizure-safe",
5897
+ nameKey: "profile.seizureSafe",
5898
+ descKey: "profile.seizureSafe.desc",
5899
+ iconId: "shield",
5900
+ features: ["animation-stop", "saturation"],
5901
+ featureSettings: { saturation: "low" }
5902
+ },
5903
+ {
5904
+ id: "adhd-friendly",
5905
+ nameKey: "profile.adhdFriendly",
5906
+ descKey: "profile.adhdFriendly.desc",
5907
+ iconId: "focus",
5908
+ features: ["animation-stop", "reading-mask", "hide-images"]
5909
+ }
5910
+ ];
5911
+ var root_3$2 = /* @__PURE__ */ from_svg(`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>`);
5912
+ var root_2$2 = /* @__PURE__ */ from_html(`<button class="accessify-accordion-option"><span class="accessify-accordion-option-left"><span class="accessify-accordion-option-icon" aria-hidden="true"></span> <span class="accessify-accordion-option-text"><span class="accessify-accordion-option-name"> </span> <span class="accessify-accordion-option-desc"> </span></span></span> <!></button>`);
5913
+ var root_1$3 = /* @__PURE__ */ from_html(`<div class="accessify-accordion-list" role="group"></div>`);
5914
+ var root$3 = /* @__PURE__ */ from_html(`<div class="accessify-accordion" role="region"><button class="accessify-accordion-toggle"><span class="accessify-accordion-toggle-left"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><path d="M12 8v4l2 2"></path></svg> <span> </span></span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></button> <!></div>`);
5915
+ function ProfileSection($$anchor, $$props) {
5912
5916
  push($$props, true);
5913
- let activeCount = prop($$props, "activeCount", 3, 0), lang = prop($$props, "lang", 3, "en");
5914
- let statusText = /* @__PURE__ */ user_derived(() => activeCount() > 0 ? t("status.active", lang()).replace("{count}", String(activeCount())) : t("status.noActive", lang()));
5917
+ let lang = prop($$props, "lang", 3, "en"), activeProfileId = prop($$props, "activeProfileId", 3, null);
5918
+ let isOpen = /* @__PURE__ */ state(false);
5919
+ function getIcon(iconId) {
5920
+ const iconFn = icons[iconId];
5921
+ return iconFn ? iconFn() : "";
5922
+ }
5923
+ let activeProfile = /* @__PURE__ */ user_derived(() => activeProfileId() ? PROFILES.find((p) => p.id === activeProfileId()) : null);
5915
5924
  var div = root$3();
5916
- var span = child(div);
5917
- var text = child(span);
5918
- var node = sibling(span, 2);
5925
+ var button = child(div);
5926
+ var span = child(button);
5927
+ var span_1 = sibling(child(span), 2);
5928
+ var text = child(span_1);
5929
+ var svg = sibling(span, 2);
5930
+ let classes;
5931
+ var node = sibling(button, 2);
5919
5932
  {
5920
- var consequent = ($$anchor2) => {
5921
- var button = root_1$2();
5922
- var text_1 = child(button);
5923
- template_effect(($0) => set_text(text_1, $0), [() => t("widget.reset", lang())]);
5924
- delegated("click", button, function(...$$args) {
5925
- $$props.onreset?.apply(this, $$args);
5933
+ var consequent_1 = ($$anchor2) => {
5934
+ var div_1 = root_1$3();
5935
+ each(div_1, 21, () => PROFILES, (profile) => profile.id, ($$anchor3, profile) => {
5936
+ var button_1 = root_2$2();
5937
+ var span_2 = child(button_1);
5938
+ var span_3 = child(span_2);
5939
+ html(span_3, () => getIcon(get(profile).iconId), true);
5940
+ var span_4 = sibling(span_3, 2);
5941
+ var span_5 = child(span_4);
5942
+ var text_1 = child(span_5);
5943
+ var span_6 = sibling(span_5, 2);
5944
+ var text_2 = child(span_6);
5945
+ var node_1 = sibling(span_2, 2);
5946
+ {
5947
+ var consequent = ($$anchor4) => {
5948
+ var svg_1 = root_3$2();
5949
+ append($$anchor4, svg_1);
5950
+ };
5951
+ if_block(node_1, ($$render) => {
5952
+ if (activeProfileId() === get(profile).id) $$render(consequent);
5953
+ });
5954
+ }
5955
+ template_effect(
5956
+ ($0, $1) => {
5957
+ set_attribute(button_1, "aria-pressed", activeProfileId() === get(profile).id);
5958
+ set_attribute(button_1, "data-active", activeProfileId() === get(profile).id);
5959
+ set_text(text_1, $0);
5960
+ set_text(text_2, $1);
5961
+ },
5962
+ [
5963
+ () => t(get(profile).nameKey, lang()),
5964
+ () => t(get(profile).descKey, lang())
5965
+ ]
5966
+ );
5967
+ delegated("click", button_1, () => $$props.onactivate(get(profile)));
5968
+ append($$anchor3, button_1);
5926
5969
  });
5927
- append($$anchor2, button);
5970
+ template_effect(($0) => set_attribute(div_1, "aria-label", $0), [() => t("section.profiles", lang())]);
5971
+ append($$anchor2, div_1);
5928
5972
  };
5929
5973
  if_block(node, ($$render) => {
5930
- if (activeCount() > 0) $$render(consequent);
5974
+ if (get(isOpen)) $$render(consequent_1);
5931
5975
  });
5932
5976
  }
5933
- template_effect(() => {
5934
- set_attribute(span, "data-count", activeCount());
5935
- set_text(text, get(statusText));
5977
+ template_effect(
5978
+ ($0, $1) => {
5979
+ set_attribute(div, "aria-label", $0);
5980
+ set_attribute(button, "aria-expanded", get(isOpen));
5981
+ set_text(text, $1);
5982
+ classes = set_class(svg, 0, "accessify-accordion-chevron", null, classes, { "accessify-accordion-chevron--open": get(isOpen) });
5983
+ },
5984
+ [
5985
+ () => t("section.profiles", lang()),
5986
+ () => get(activeProfile) ? t(get(activeProfile).nameKey, lang()) : t("section.profiles", lang())
5987
+ ]
5988
+ );
5989
+ delegated("click", button, () => {
5990
+ set(isOpen, !get(isOpen));
5936
5991
  });
5937
5992
  append($$anchor, div);
5938
5993
  pop();
@@ -5941,10 +5996,13 @@ delegate(["click"]);
5941
5996
  const DEFAULT_PROXY = "https://accessify-api.accessify.workers.dev";
5942
5997
  const OPENROUTER_BASE = "https://openrouter.ai/api/v1";
5943
5998
  const DEFAULTS = {
5944
- textModel: "qwen/qwen3-next-80b-a3b-instruct:free",
5945
- visionModel: "meta-llama/llama-3.3-70b-instruct:free"
5999
+ textModel: "google/gemini-2.0-flash-001",
6000
+ visionModel: "google/gemini-2.0-flash-001"
5946
6001
  };
5947
6002
  function createAIService(config2) {
6003
+ if (config2.apiKey) {
6004
+ return createDirectService(config2);
6005
+ }
5948
6006
  if (config2.siteKey) {
5949
6007
  return createProxyService(config2.siteKey, config2.proxyUrl);
5950
6008
  }
@@ -5958,6 +6016,42 @@ function createProxyService(siteKey, proxyUrl) {
5958
6016
  };
5959
6017
  return {
5960
6018
  async simplifyText(text, level = "einfache", lang = "de") {
6019
+ const blockId = `b-${simpleHash(text)}`;
6020
+ const variant = lang.startsWith("de") ? `de-${level}` : "en-plain";
6021
+ try {
6022
+ const cacheRes = await fetch(`${base}/v1/cache/query`, {
6023
+ method: "POST",
6024
+ headers,
6025
+ body: JSON.stringify({
6026
+ pageUrl: typeof window !== "undefined" ? window.location.href : "",
6027
+ feature: "simplify",
6028
+ variant,
6029
+ blocks: [{ id: blockId, text }]
6030
+ })
6031
+ });
6032
+ if (cacheRes.ok) {
6033
+ const cacheData = await cacheRes.json();
6034
+ if (cacheData.cached?.[blockId]) return cacheData.cached[blockId];
6035
+ }
6036
+ } catch {
6037
+ }
6038
+ try {
6039
+ const processRes = await fetch(`${base}/v1/cache/process`, {
6040
+ method: "POST",
6041
+ headers,
6042
+ body: JSON.stringify({
6043
+ pageUrl: typeof window !== "undefined" ? window.location.href : "",
6044
+ feature: "simplify",
6045
+ variant,
6046
+ blocks: [{ id: blockId, text }]
6047
+ })
6048
+ });
6049
+ if (processRes.ok) {
6050
+ const processData = await processRes.json();
6051
+ if (processData.results?.[blockId]) return processData.results[blockId];
6052
+ }
6053
+ } catch {
6054
+ }
5961
6055
  const res = await fetch(`${base}/v1/ai/simplify`, {
5962
6056
  method: "POST",
5963
6057
  headers,
@@ -5971,11 +6065,11 @@ function createProxyService(siteKey, proxyUrl) {
5971
6065
  const data = await res.json();
5972
6066
  return data.result || "";
5973
6067
  },
5974
- async generateAltText(imageUrl, context) {
6068
+ async generateAltText(imageUrl, context, lang) {
5975
6069
  const res = await fetch(`${base}/v1/ai/alt-text`, {
5976
6070
  method: "POST",
5977
6071
  headers,
5978
- body: JSON.stringify({ imageUrl, context })
6072
+ body: JSON.stringify({ imageUrl, context, lang })
5979
6073
  });
5980
6074
  if (!res.ok) {
5981
6075
  const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
@@ -5987,6 +6081,25 @@ function createProxyService(siteKey, proxyUrl) {
5987
6081
  }
5988
6082
  };
5989
6083
  }
6084
+ function simpleHash(str) {
6085
+ let hash = 5381;
6086
+ for (let i = 0; i < str.length; i++) {
6087
+ hash = (hash << 5) + hash + str.charCodeAt(i);
6088
+ hash |= 0;
6089
+ }
6090
+ return Math.abs(hash).toString(36);
6091
+ }
6092
+ function extractContent(data) {
6093
+ const msg = data.choices?.[0]?.message;
6094
+ if (msg?.content && typeof msg.content === "string") return msg.content.trim();
6095
+ if (msg?.reasoning && typeof msg.reasoning === "string") return msg.reasoning.trim();
6096
+ if (Array.isArray(msg?.reasoning_details)) {
6097
+ for (const detail of msg.reasoning_details) {
6098
+ if (detail?.text) return detail.text.trim();
6099
+ }
6100
+ }
6101
+ return "";
6102
+ }
5990
6103
  function createDirectService(config2) {
5991
6104
  const headers = {
5992
6105
  "Content-Type": "application/json",
@@ -6015,9 +6128,10 @@ function createDirectService(config2) {
6015
6128
  throw new Error(`AI service error: ${response.status}`);
6016
6129
  }
6017
6130
  const data = await response.json();
6018
- return data.choices?.[0]?.message?.content?.trim() || "";
6131
+ return extractContent(data);
6019
6132
  },
6020
- async generateAltText(imageUrl, context) {
6133
+ async generateAltText(imageUrl, context, lang) {
6134
+ const langInstruction = lang && !lang.startsWith("en") ? ` Generate the alt text in ${lang} language.` : "";
6021
6135
  const response = await fetch(`${OPENROUTER_BASE}/chat/completions`, {
6022
6136
  method: "POST",
6023
6137
  headers,
@@ -6028,12 +6142,12 @@ function createDirectService(config2) {
6028
6142
  content: [
6029
6143
  {
6030
6144
  type: "text",
6031
- text: `Generate a concise, descriptive alt text for this image for web accessibility. ${context ? "Context: " + context : ""} Return ONLY the alt text, nothing else. Max 125 characters.`
6145
+ text: `Generate a concise, descriptive alt text for this image for web accessibility.${langInstruction} ${context ? "Context: " + context : ""} Return ONLY the alt text, nothing else. Max 125 characters.`
6032
6146
  },
6033
6147
  { type: "image_url", image_url: { url: imageUrl } }
6034
6148
  ]
6035
6149
  }],
6036
- max_tokens: 100
6150
+ max_tokens: 300
6037
6151
  })
6038
6152
  });
6039
6153
  if (!response.ok) {
@@ -6041,7 +6155,7 @@ function createDirectService(config2) {
6041
6155
  throw new Error(`AI vision error: ${response.status}`);
6042
6156
  }
6043
6157
  const data = await response.json();
6044
- return data.choices?.[0]?.message?.content?.trim() || "";
6158
+ return extractContent(data);
6045
6159
  }
6046
6160
  };
6047
6161
  }
@@ -6086,16 +6200,12 @@ function getEnglishSimplificationPrompt() {
6086
6200
 
6087
6201
  Return ONLY the simplified text.`;
6088
6202
  }
6089
- var root_3 = /* @__PURE__ */ from_html(`<button class="accessify-chip"> </button>`);
6090
- var root_2 = /* @__PURE__ */ from_html(`<article class="accessify-control-card accessify-control-card--contrast"><div class="accessify-control-copy"><span class="accessify-card-icon" aria-hidden="true"></span> <div><h4> </h4> <p> </p></div></div> <div class="accessify-chip-group" role="group"></div></article>`);
6091
- var root_5 = /* @__PURE__ */ from_html(`<button class="accessify-chip"> </button>`);
6092
- var root_4 = /* @__PURE__ */ from_html(`<article class="accessify-control-card accessify-control-card--text-size"><div class="accessify-control-copy"><span class="accessify-card-icon" aria-hidden="true"></span> <div><h4> </h4> <p> </p></div></div> <div class="accessify-chip-group accessify-chip-group--sizes" role="group"></div></article>`);
6093
- var root_7 = /* @__PURE__ */ from_html(`<button class="accessify-card" role="switch"><div class="accessify-card-top"><span class="accessify-card-icon" aria-hidden="true"></span></div> <span class="accessify-card-label"> </span> <span class="accessify-card-desc"> </span></button>`);
6094
- var root_6 = /* @__PURE__ */ from_html(`<div class="accessify-features"></div>`);
6095
- var root_1$1 = /* @__PURE__ */ from_html(`<section class="accessify-section accessify-section--priority"><div class="accessify-section-head"><div><h3> </h3> <p> </p></div></div> <div class="accessify-control-grid"><!> <!></div> <!></section>`);
6096
- var root_10 = /* @__PURE__ */ from_html(`<button class="accessify-card" role="switch"><div class="accessify-card-top"><span class="accessify-card-icon" aria-hidden="true"></span></div> <span class="accessify-card-label"> </span> <span class="accessify-card-desc"> </span></button>`);
6097
- var root_9 = /* @__PURE__ */ from_html(`<section><div class="accessify-section-head"><div><h3> </h3> <p> </p></div></div> <div class="accessify-features"></div></section>`);
6098
- var root$2 = /* @__PURE__ */ from_html(`<div class="accessify-body"><!> <!></div>`);
6203
+ var root_2$1 = /* @__PURE__ */ from_html(`<button class="accessify-chip accessify-chip--icon"><span class="accessify-chip-icon" aria-hidden="true"></span> <span> </span></button>`);
6204
+ var root_1$2 = /* @__PURE__ */ from_html(`<div class="accessify-control-row" role="group"><div class="accessify-control-label"><span class="accessify-control-label-icon" aria-hidden="true"></span> <span class="accessify-control-label-text"> </span></div> <div class="accessify-chip-row"></div></div>`);
6205
+ var root_3$1 = /* @__PURE__ */ from_html(`<div class="accessify-control-row" role="group"><div class="accessify-control-label"><span class="accessify-control-label-icon" aria-hidden="true"></span> <span class="accessify-control-label-text"> </span></div> <div class="accessify-stepper"><button class="accessify-stepper-btn" aria-label="Decrease text size">−</button> <span class="accessify-stepper-value" aria-live="polite"> </span> <button class="accessify-stepper-btn" aria-label="Increase text size">+</button></div></div>`);
6206
+ var root_5 = /* @__PURE__ */ from_html(`<div class="accessify-card-wrap"><button class="accessify-card" role="switch"><span class="accessify-card-icon" aria-hidden="true"></span> <span class="accessify-card-label"> </span></button> <span class="accessify-card-info" tabindex="0"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg> <span class="accessify-card-tooltip"> </span></span></div>`);
6207
+ var root_4 = /* @__PURE__ */ from_html(`<div class="accessify-features"></div>`);
6208
+ var root$2 = /* @__PURE__ */ from_html(`<!> <!> <div class="accessify-section-divider"></div> <!>`, 1);
6099
6209
  function FeatureGrid($$anchor, $$props) {
6100
6210
  push($$props, true);
6101
6211
  const FEATURE_REGISTRY = {
@@ -6105,12 +6215,6 @@ function FeatureGrid($$anchor, $$props) {
6105
6215
  descKey: "feature.keyboardNav.desc",
6106
6216
  iconId: "keyboard"
6107
6217
  },
6108
- "focus-highlight": {
6109
- id: "focus-highlight",
6110
- nameKey: "feature.focusHighlight",
6111
- descKey: "feature.focusHighlight.desc",
6112
- iconId: "focus"
6113
- },
6114
6218
  "link-highlight": {
6115
6219
  id: "link-highlight",
6116
6220
  nameKey: "feature.linkHighlight",
@@ -6170,72 +6274,57 @@ function FeatureGrid($$anchor, $$props) {
6170
6274
  nameKey: "feature.altText",
6171
6275
  descKey: "feature.altText.desc",
6172
6276
  iconId: "alt-text"
6173
- },
6174
- "auto-scan": {
6175
- id: "auto-scan",
6176
- nameKey: "feature.autoScan",
6177
- descKey: "feature.autoScan.desc",
6178
- iconId: "scan"
6179
6277
  }
6180
6278
  };
6181
- const SECTIONS = [
6279
+ const VISUAL_IDS = [
6280
+ "keyboard-nav",
6281
+ "link-highlight",
6282
+ "animation-stop",
6283
+ "hide-images",
6284
+ "big-cursor"
6285
+ ];
6286
+ const READING_IDS = ["reading-guide", "reading-mask", "tts"];
6287
+ const AI_IDS = ["text-simplify", "alt-text"];
6288
+ const CONTRAST_MODES = [
6182
6289
  {
6183
- id: "essentials",
6184
- labelKey: "section.essentials",
6185
- descKey: "section.essentials.desc",
6186
- featureIds: ["keyboard-nav", "focus-highlight", "link-highlight"]
6290
+ id: "light",
6291
+ labelKey: "contrast.mode.light",
6292
+ icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>'
6187
6293
  },
6188
6294
  {
6189
- id: "support",
6190
- labelKey: "section.support",
6191
- descKey: "section.support.desc",
6192
- featureIds: [
6193
- "reading-guide",
6194
- "reading-mask",
6195
- "animation-stop",
6196
- "hide-images",
6197
- "page-structure",
6198
- "big-cursor",
6199
- "tts"
6200
- ]
6295
+ id: "dark",
6296
+ labelKey: "contrast.mode.dark",
6297
+ icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>'
6201
6298
  },
6202
6299
  {
6203
- id: "ai",
6204
- labelKey: "section.ai",
6205
- descKey: "section.ai.desc",
6206
- featureIds: ["text-simplify", "alt-text", "auto-scan"]
6300
+ id: "high",
6301
+ labelKey: "contrast.mode.high",
6302
+ icon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2v20"/><path d="M12 2a10 10 0 0 1 0 20" fill="currentColor"/></svg>'
6207
6303
  }
6208
6304
  ];
6209
- const CONTRAST_MODES = [
6210
- { id: "off", labelKey: "control.default" },
6211
- { id: "light", labelKey: "contrast.mode.light" },
6212
- { id: "dark", labelKey: "contrast.mode.dark" },
6213
- { id: "high", labelKey: "contrast.mode.high" }
6214
- ];
6215
- const TEXT_SIZE_PRESETS = [100, 120, 140, 160, 180];
6305
+ const TEXT_SIZE_MIN = 100;
6306
+ const TEXT_SIZE_MAX = 200;
6307
+ const TEXT_SIZE_STEP = 10;
6216
6308
  const AI_FEATURES = /* @__PURE__ */ new Set(["text-simplify", "alt-text"]);
6217
6309
  const loadedModules = /* @__PURE__ */ new Map();
6218
6310
  const FEATURE_LOADERS = {
6219
6311
  contrast: () => import("./contrast-CqsICAkU.js"),
6220
6312
  "text-size": () => import("./text-size-C6OFhCGi.js"),
6221
- "keyboard-nav": () => import("./keyboard-nav-DH4qBThF.js"),
6222
- "focus-highlight": () => import("./focus-highlight-CjERyyUF.js"),
6313
+ "keyboard-nav": () => import("./keyboard-nav-CkAYxUc1.js"),
6223
6314
  "link-highlight": () => import("./link-highlight-DBGm067Y.js"),
6224
6315
  "reading-guide": () => import("./reading-guide-VT8NciIL.js"),
6225
6316
  "reading-mask": () => import("./reading-mask-BABChuCz.js"),
6226
6317
  "animation-stop": () => import("./animation-stop-DXebPS8D.js"),
6227
6318
  "hide-images": () => import("./hide-images-DJwmsV2C.js"),
6228
6319
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6229
- "page-structure": () => import("./page-structure-DTBqkrYs.js"),
6230
- tts: () => import("./tts-02b9iV0h.js"),
6231
- "text-simplify": () => import("./text-simplify-CELklw5A.js"),
6232
- "alt-text": () => import("./alt-text-CgzNGvdT.js"),
6233
- "auto-scan": () => import("./auto-scan-pg-09o7A.js")
6320
+ "page-structure": () => import("./page-structure-yWkBKmwo.js"),
6321
+ tts: () => import("./tts-CjszLRnb.js"),
6322
+ "text-simplify": () => import("./text-simplify-C9gzE3t0.js"),
6323
+ "alt-text": () => Promise.resolve().then(() => altText)
6234
6324
  };
6235
6325
  let contrastMode = /* @__PURE__ */ state(proxy(readStoredContrastMode()));
6236
6326
  let textSize = /* @__PURE__ */ state(proxy(readStoredTextSize()));
6237
6327
  let visibleFeatureIds = /* @__PURE__ */ user_derived(() => new Set($$props.config.features));
6238
- let essentialFeatures = /* @__PURE__ */ user_derived(() => getFeatureDefs(SECTIONS[0].featureIds));
6239
6328
  let activeSignature = /* @__PURE__ */ user_derived(() => Array.from($$props.activeFeatures.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([id, enabled]) => `${id}:${enabled}`).join("|"));
6240
6329
  let aiService;
6241
6330
  function readStoredContrastMode() {
@@ -6262,7 +6351,7 @@ function FeatureGrid($$anchor, $$props) {
6262
6351
  const iconFn = icons[iconId];
6263
6352
  return iconFn ? iconFn() : "";
6264
6353
  }
6265
- function getFeatureDefs(ids) {
6354
+ function getVisibleFeatures(ids) {
6266
6355
  return ids.filter((id) => get(visibleFeatureIds).has(id)).map((id) => FEATURE_REGISTRY[id]).filter(Boolean);
6267
6356
  }
6268
6357
  function updateControlState(id, module) {
@@ -6295,7 +6384,10 @@ function FeatureGrid($$anchor, $$props) {
6295
6384
  try {
6296
6385
  const mod = await loader();
6297
6386
  const exported = mod.default ?? mod;
6298
- const featureModule = typeof exported === "function" ? AI_FEATURES.has(id) ? exported(getAIService(), $$props.config.lang) : exported() : exported;
6387
+ const featureModule = typeof exported === "function" ? AI_FEATURES.has(id) ? exported(getAIService(), $$props.config.lang, {
6388
+ siteKey: $$props.config.siteKey,
6389
+ proxyUrl: $$props.config.proxyUrl
6390
+ }) : exported() : exported;
6299
6391
  loadedModules.set(id, featureModule);
6300
6392
  return featureModule;
6301
6393
  } catch (error) {
@@ -6360,248 +6452,165 @@ function FeatureGrid($$anchor, $$props) {
6360
6452
  set(textSize, value, true);
6361
6453
  $$props.ontoggle("text-size", true);
6362
6454
  }
6455
+ let visualFeatures = /* @__PURE__ */ user_derived(() => getVisibleFeatures(VISUAL_IDS));
6456
+ let readingFeatures = /* @__PURE__ */ user_derived(() => getVisibleFeatures(READING_IDS));
6457
+ let aiFeatures = /* @__PURE__ */ user_derived(() => getVisibleFeatures(AI_IDS));
6363
6458
  user_effect(() => {
6364
6459
  `${$$props.config.features.join("|")}|${get(activeSignature)}`;
6365
6460
  void syncActiveModules();
6366
6461
  });
6367
- var div = root$2();
6368
- var node = child(div);
6462
+ var fragment = root$2();
6463
+ var node = first_child(fragment);
6369
6464
  {
6370
- var consequent_3 = ($$anchor2) => {
6371
- var section_1 = root_1$1();
6372
- var div_1 = child(section_1);
6373
- var div_2 = child(div_1);
6374
- var h3 = child(div_2);
6375
- var text = child(h3);
6376
- var p = sibling(h3, 2);
6377
- var text_1 = child(p);
6378
- var div_3 = sibling(div_1, 2);
6379
- var node_1 = child(div_3);
6380
- {
6381
- var consequent = ($$anchor3) => {
6382
- var article = root_2();
6383
- var div_4 = child(article);
6384
- var span = child(div_4);
6385
- html(span, () => getIcon("contrast"), true);
6386
- var div_5 = sibling(span, 2);
6387
- var h4 = child(div_5);
6388
- var text_2 = child(h4);
6389
- var p_1 = sibling(h4, 2);
6390
- var text_3 = child(p_1);
6391
- var div_6 = sibling(div_4, 2);
6392
- each(div_6, 21, () => CONTRAST_MODES, index, ($$anchor4, mode) => {
6393
- var button = root_3();
6394
- var text_4 = child(button);
6395
- template_effect(
6396
- ($0) => {
6397
- set_attribute(button, "data-active", get(contrastMode) === get(mode).id);
6398
- set_attribute(button, "aria-pressed", get(contrastMode) === get(mode).id);
6399
- set_text(text_4, $0);
6400
- },
6401
- [() => t(get(mode).labelKey, $$props.config.lang)]
6402
- );
6403
- delegated("click", button, () => setContrastMode(get(mode).id));
6404
- append($$anchor4, button);
6405
- });
6406
- template_effect(
6407
- ($0, $1, $2) => {
6408
- set_text(text_2, $0);
6409
- set_text(text_3, $1);
6410
- set_attribute(div_6, "aria-label", $2);
6411
- },
6412
- [
6413
- () => t("feature.contrast", $$props.config.lang),
6414
- () => t("feature.contrast.desc", $$props.config.lang),
6415
- () => t("control.chooseMode", $$props.config.lang)
6416
- ]
6417
- );
6418
- append($$anchor3, article);
6419
- };
6420
- var d = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("contrast"));
6421
- if_block(node_1, ($$render) => {
6422
- if (get(d)) $$render(consequent);
6423
- });
6424
- }
6425
- var node_2 = sibling(node_1, 2);
6426
- {
6427
- var consequent_1 = ($$anchor3) => {
6428
- var article_1 = root_4();
6429
- var div_7 = child(article_1);
6430
- var span_1 = child(div_7);
6431
- html(span_1, () => getIcon("text-size"), true);
6432
- var div_8 = sibling(span_1, 2);
6433
- var h4_1 = child(div_8);
6434
- var text_5 = child(h4_1);
6435
- var p_2 = sibling(h4_1, 2);
6436
- var text_6 = child(p_2);
6437
- var div_9 = sibling(div_7, 2);
6438
- each(div_9, 21, () => TEXT_SIZE_PRESETS, index, ($$anchor4, preset) => {
6439
- var button_1 = root_5();
6440
- var text_7 = child(button_1);
6441
- template_effect(() => {
6442
- set_attribute(button_1, "data-active", get(textSize) === get(preset));
6443
- set_attribute(button_1, "aria-pressed", get(textSize) === get(preset));
6444
- set_text(text_7, `${get(preset) ?? ""}%`);
6445
- });
6446
- delegated("click", button_1, () => setTextSize(get(preset)));
6447
- append($$anchor4, button_1);
6448
- });
6449
- template_effect(
6450
- ($0, $1, $2) => {
6451
- set_text(text_5, $0);
6452
- set_text(text_6, $1);
6453
- set_attribute(div_9, "aria-label", $2);
6454
- },
6455
- [
6456
- () => t("feature.textSize", $$props.config.lang),
6457
- () => t("feature.textSize.desc", $$props.config.lang),
6458
- () => t("feature.textSize", $$props.config.lang)
6459
- ]
6460
- );
6461
- append($$anchor3, article_1);
6462
- };
6463
- var d_1 = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("text-size"));
6464
- if_block(node_2, ($$render) => {
6465
- if (get(d_1)) $$render(consequent_1);
6466
- });
6467
- }
6468
- var node_3 = sibling(div_3, 2);
6469
- {
6470
- var consequent_2 = ($$anchor3) => {
6471
- var div_10 = root_6();
6472
- each(div_10, 21, () => get(essentialFeatures), (feature) => feature.id, ($$anchor4, feature) => {
6473
- const isActive = /* @__PURE__ */ user_derived(() => $$props.activeFeatures.get(get(feature).id) ?? false);
6474
- var button_2 = root_7();
6475
- var div_11 = child(button_2);
6476
- var span_2 = child(div_11);
6477
- html(span_2, () => getIcon(get(feature).iconId), true);
6478
- var span_3 = sibling(div_11, 2);
6479
- var text_8 = child(span_3);
6480
- var span_4 = sibling(span_3, 2);
6481
- var text_9 = child(span_4);
6482
- template_effect(
6483
- ($0, $1, $2) => {
6484
- set_attribute(button_2, "data-active", get(isActive));
6485
- set_attribute(button_2, "aria-checked", get(isActive));
6486
- set_attribute(button_2, "aria-label", $0);
6487
- set_text(text_8, $1);
6488
- set_text(text_9, $2);
6489
- },
6490
- [
6491
- () => t(get(feature).nameKey, $$props.config.lang),
6492
- () => t(get(feature).nameKey, $$props.config.lang),
6493
- () => t(get(feature).descKey, $$props.config.lang)
6494
- ]
6495
- );
6496
- delegated("click", button_2, () => handleToggle(get(feature).id));
6497
- append($$anchor4, button_2);
6498
- });
6499
- append($$anchor3, div_10);
6500
- };
6501
- if_block(node_3, ($$render) => {
6502
- if (get(essentialFeatures).length > 0) $$render(consequent_2);
6503
- });
6504
- }
6465
+ var consequent = ($$anchor2) => {
6466
+ var div = root_1$2();
6467
+ var div_1 = child(div);
6468
+ var span = child(div_1);
6469
+ html(span, () => getIcon("contrast"), true);
6470
+ var span_1 = sibling(span, 2);
6471
+ var text = child(span_1);
6472
+ var div_2 = sibling(div_1, 2);
6473
+ each(div_2, 21, () => CONTRAST_MODES, index, ($$anchor3, mode) => {
6474
+ var button = root_2$1();
6475
+ var span_2 = child(button);
6476
+ html(span_2, () => get(mode).icon, true);
6477
+ var span_3 = sibling(span_2, 2);
6478
+ var text_1 = child(span_3);
6479
+ template_effect(
6480
+ ($0) => {
6481
+ set_attribute(button, "data-active", get(contrastMode) === get(mode).id);
6482
+ set_attribute(button, "aria-pressed", get(contrastMode) === get(mode).id);
6483
+ set_text(text_1, $0);
6484
+ },
6485
+ [() => t(get(mode).labelKey, $$props.config.lang)]
6486
+ );
6487
+ delegated("click", button, () => setContrastMode(get(contrastMode) === get(mode).id ? "off" : get(mode).id));
6488
+ append($$anchor3, button);
6489
+ });
6505
6490
  template_effect(
6506
6491
  ($0, $1) => {
6507
- set_text(text, $0);
6508
- set_text(text_1, $1);
6492
+ set_attribute(div, "aria-label", $0);
6493
+ set_text(text, $1);
6509
6494
  },
6510
6495
  [
6511
- () => t(SECTIONS[0].labelKey, $$props.config.lang),
6512
- () => t(SECTIONS[0].descKey, $$props.config.lang)
6496
+ () => t("feature.contrast", $$props.config.lang),
6497
+ () => t("feature.contrast", $$props.config.lang)
6513
6498
  ]
6514
6499
  );
6515
- append($$anchor2, section_1);
6500
+ append($$anchor2, div);
6516
6501
  };
6517
- var d_2 = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("contrast") || get(visibleFeatureIds).has("text-size") || getFeatureDefs(SECTIONS[0].featureIds).length > 0);
6502
+ var d = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("contrast"));
6518
6503
  if_block(node, ($$render) => {
6519
- if (get(d_2)) $$render(consequent_3);
6504
+ if (get(d)) $$render(consequent);
6520
6505
  });
6521
6506
  }
6522
- var node_4 = sibling(node, 2);
6523
- each(node_4, 17, () => SECTIONS.slice(1), index, ($$anchor2, section) => {
6524
- const features = /* @__PURE__ */ user_derived(() => getFeatureDefs(get(section).featureIds));
6525
- var fragment = comment();
6526
- var node_5 = first_child(fragment);
6527
- {
6528
- var consequent_4 = ($$anchor3) => {
6529
- var section_2 = root_9();
6530
- var div_12 = child(section_2);
6531
- var div_13 = child(div_12);
6532
- var h3_1 = child(div_13);
6533
- var text_10 = child(h3_1);
6534
- var p_3 = sibling(h3_1, 2);
6535
- var text_11 = child(p_3);
6536
- var div_14 = sibling(div_12, 2);
6537
- each(div_14, 21, () => get(features), (feature) => feature.id, ($$anchor4, feature) => {
6507
+ var node_1 = sibling(node, 2);
6508
+ {
6509
+ var consequent_1 = ($$anchor2) => {
6510
+ var div_3 = root_3$1();
6511
+ var div_4 = child(div_3);
6512
+ var span_4 = child(div_4);
6513
+ html(span_4, () => getIcon("text-size"), true);
6514
+ var span_5 = sibling(span_4, 2);
6515
+ var text_2 = child(span_5);
6516
+ var div_5 = sibling(div_4, 2);
6517
+ var button_1 = child(div_5);
6518
+ var span_6 = sibling(button_1, 2);
6519
+ var text_3 = child(span_6);
6520
+ var button_2 = sibling(span_6, 2);
6521
+ template_effect(
6522
+ ($0, $1) => {
6523
+ set_attribute(div_3, "aria-label", $0);
6524
+ set_text(text_2, $1);
6525
+ button_1.disabled = get(textSize) <= TEXT_SIZE_MIN;
6526
+ set_text(text_3, `${get(textSize) ?? ""}%`);
6527
+ button_2.disabled = get(textSize) >= TEXT_SIZE_MAX;
6528
+ },
6529
+ [
6530
+ () => t("feature.textSize", $$props.config.lang),
6531
+ () => t("feature.textSize", $$props.config.lang)
6532
+ ]
6533
+ );
6534
+ delegated("click", button_1, () => setTextSize(Math.max(TEXT_SIZE_MIN, get(textSize) - TEXT_SIZE_STEP)));
6535
+ delegated("click", button_2, () => setTextSize(Math.min(TEXT_SIZE_MAX, get(textSize) + TEXT_SIZE_STEP)));
6536
+ append($$anchor2, div_3);
6537
+ };
6538
+ var d_1 = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("text-size"));
6539
+ if_block(node_1, ($$render) => {
6540
+ if (get(d_1)) $$render(consequent_1);
6541
+ });
6542
+ }
6543
+ var node_2 = sibling(node_1, 4);
6544
+ {
6545
+ var consequent_2 = ($$anchor2) => {
6546
+ var div_6 = root_4();
6547
+ each(
6548
+ div_6,
6549
+ 21,
6550
+ () => [
6551
+ ...get(visualFeatures),
6552
+ ...get(readingFeatures),
6553
+ ...get(aiFeatures)
6554
+ ],
6555
+ (feature) => feature.id,
6556
+ ($$anchor3, feature) => {
6538
6557
  const isActive = /* @__PURE__ */ user_derived(() => $$props.activeFeatures.get(get(feature).id) ?? false);
6539
- var button_3 = root_10();
6540
- var div_15 = child(button_3);
6541
- var span_5 = child(div_15);
6542
- html(span_5, () => getIcon(get(feature).iconId), true);
6543
- var span_6 = sibling(div_15, 2);
6544
- var text_12 = child(span_6);
6545
- var span_7 = sibling(span_6, 2);
6546
- var text_13 = child(span_7);
6558
+ var div_7 = root_5();
6559
+ var button_3 = child(div_7);
6560
+ var span_7 = child(button_3);
6561
+ html(span_7, () => getIcon(get(feature).iconId), true);
6562
+ var span_8 = sibling(span_7, 2);
6563
+ var text_4 = child(span_8);
6564
+ var span_9 = sibling(button_3, 2);
6565
+ var span_10 = sibling(child(span_9), 2);
6566
+ var text_5 = child(span_10);
6547
6567
  template_effect(
6548
- ($0, $1, $2) => {
6568
+ ($0, $1, $2, $3) => {
6549
6569
  set_attribute(button_3, "data-active", get(isActive));
6550
6570
  set_attribute(button_3, "aria-checked", get(isActive));
6551
6571
  set_attribute(button_3, "aria-label", $0);
6552
- set_text(text_12, $1);
6553
- set_text(text_13, $2);
6572
+ set_text(text_4, $1);
6573
+ set_attribute(span_9, "aria-label", $2);
6574
+ set_text(text_5, $3);
6554
6575
  },
6555
6576
  [
6556
6577
  () => t(get(feature).nameKey, $$props.config.lang),
6557
6578
  () => t(get(feature).nameKey, $$props.config.lang),
6579
+ () => t(get(feature).descKey, $$props.config.lang),
6558
6580
  () => t(get(feature).descKey, $$props.config.lang)
6559
6581
  ]
6560
6582
  );
6561
6583
  delegated("click", button_3, () => handleToggle(get(feature).id));
6562
- append($$anchor4, button_3);
6563
- });
6564
- template_effect(
6565
- ($0, $1) => {
6566
- set_class(section_2, 1, `accessify-section accessify-section--${get(section).id}`);
6567
- set_text(text_10, $0);
6568
- set_text(text_11, $1);
6569
- },
6570
- [
6571
- () => t(get(section).labelKey, $$props.config.lang),
6572
- () => t(get(section).descKey, $$props.config.lang)
6573
- ]
6574
- );
6575
- append($$anchor3, section_2);
6576
- };
6577
- if_block(node_5, ($$render) => {
6578
- if (get(features).length > 0) $$render(consequent_4);
6579
- });
6580
- }
6581
- append($$anchor2, fragment);
6582
- });
6583
- append($$anchor, div);
6584
+ append($$anchor3, div_7);
6585
+ }
6586
+ );
6587
+ append($$anchor2, div_6);
6588
+ };
6589
+ if_block(node_2, ($$render) => {
6590
+ if (get(visualFeatures).length > 0 || get(readingFeatures).length > 0 || get(aiFeatures).length > 0) $$render(consequent_2);
6591
+ });
6592
+ }
6593
+ append($$anchor, fragment);
6584
6594
  pop();
6585
6595
  }
6586
6596
  delegate(["click"]);
6587
- var root_1 = /* @__PURE__ */ from_html(`<span aria-hidden="true">&middot;</span> <a target="_blank" rel="noopener noreferrer"> </a>`, 1);
6588
- var root$1 = /* @__PURE__ */ from_html(`<div class="accessify-footer"><span> </span> <!></div>`);
6597
+ var root_1$1 = /* @__PURE__ */ from_html(`<span aria-hidden="true">&middot;</span> <a target="_blank" rel="noopener noreferrer"> </a>`, 1);
6598
+ var root$1 = /* @__PURE__ */ from_html(`<div class="accessify-footer"><a target="_blank" rel="noopener noreferrer">Accessify Dashboard</a> <!></div>`);
6589
6599
  function PanelFooter($$anchor, $$props) {
6590
6600
  push($$props, true);
6591
6601
  let lang = prop($$props, "lang", 3, "en");
6592
6602
  var div = root$1();
6593
- var span = child(div);
6594
- var text = child(span);
6595
- var node = sibling(span, 2);
6603
+ var a = child(div);
6604
+ var node = sibling(a, 2);
6596
6605
  {
6597
6606
  var consequent = ($$anchor2) => {
6598
- var fragment = root_1();
6599
- var a = sibling(first_child(fragment), 2);
6600
- var text_1 = child(a);
6607
+ var fragment = root_1$1();
6608
+ var a_1 = sibling(first_child(fragment), 2);
6609
+ var text = child(a_1);
6601
6610
  template_effect(
6602
6611
  ($0) => {
6603
- set_attribute(a, "href", $$props.statementUrl);
6604
- set_text(text_1, $0);
6612
+ set_attribute(a_1, "href", $$props.statementUrl);
6613
+ set_text(text, $0);
6605
6614
  },
6606
6615
  [() => t("widget.statement", lang())]
6607
6616
  );
@@ -6611,41 +6620,179 @@ function PanelFooter($$anchor, $$props) {
6611
6620
  if ($$props.statementUrl) $$render(consequent);
6612
6621
  });
6613
6622
  }
6614
- template_effect(($0) => set_text(text, $0), [() => t("widget.poweredBy", lang())]);
6623
+ template_effect(() => set_attribute(a, "href", $$props.dashboardUrl || "https://accessify-dashboard.pages.dev"));
6615
6624
  append($$anchor, div);
6616
6625
  pop();
6617
6626
  }
6618
- var root = /* @__PURE__ */ from_html(`<div class="sr-only" role="status" aria-live="polite" aria-atomic="true"> </div> <!> <div class="accessify-panel" role="dialog"><!> <!> <!> <!></div>`, 1);
6619
- function WidgetApp($$anchor, $$props) {
6620
- push($$props, true);
6621
- let config2 = prop($$props, "config", 7);
6622
- let isOpen = /* @__PURE__ */ state(false);
6623
- let activeFeatures = /* @__PURE__ */ state(proxy(/* @__PURE__ */ new Map()));
6624
- let currentTheme = /* @__PURE__ */ state("light");
6625
- let panelEl = /* @__PURE__ */ state(null);
6626
- let triggerEl = /* @__PURE__ */ state(null);
6627
- let announcement = /* @__PURE__ */ state("");
6628
- let widgetLang = /* @__PURE__ */ state("en");
6629
- const STORAGE_KEY = "accessify-prefs";
6630
- let activeCount = /* @__PURE__ */ user_derived(() => Array.from(get(activeFeatures).values()).filter(Boolean).length);
6631
- function announce(message) {
6632
- set(announcement, "");
6633
- requestAnimationFrame(() => {
6634
- set(announcement, message, true);
6635
- });
6636
- }
6637
- function loadPrefs() {
6638
- try {
6639
- const saved = localStorage.getItem(STORAGE_KEY);
6640
- if (saved) {
6641
- const prefs = JSON.parse(saved);
6642
- set(activeFeatures, new Map(Object.entries(prefs)), true);
6627
+ let savedNodes = [];
6628
+ let currentTranslateLang = null;
6629
+ let translating = false;
6630
+ const TRANSLATE_URL = "https://translate.googleapis.com/translate_a/single";
6631
+ async function translateSingleText(text, sourceLang, targetLang) {
6632
+ const params = new URLSearchParams({
6633
+ client: "gtx",
6634
+ sl: sourceLang,
6635
+ tl: targetLang,
6636
+ dt: "t",
6637
+ q: text
6638
+ });
6639
+ try {
6640
+ const res = await fetch(`${TRANSLATE_URL}?${params.toString()}`);
6641
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
6642
+ const data = await res.json();
6643
+ if (Array.isArray(data[0])) {
6644
+ const parts = [];
6645
+ for (const segment of data[0]) {
6646
+ if (Array.isArray(segment) && typeof segment[0] === "string") {
6647
+ parts.push(segment[0]);
6648
+ }
6643
6649
  }
6644
- } catch {
6650
+ return parts.join("");
6645
6651
  }
6652
+ return text;
6653
+ } catch {
6654
+ return text;
6646
6655
  }
6647
- function savePrefs() {
6648
- try {
6656
+ }
6657
+ async function translateTexts(texts, sourceLang, targetLang) {
6658
+ const CONCURRENCY = 10;
6659
+ const results = new Array(texts.length);
6660
+ for (let start = 0; start < texts.length; start += CONCURRENCY) {
6661
+ const batch = texts.slice(start, start + CONCURRENCY);
6662
+ const translated = await Promise.all(
6663
+ batch.map((text) => translateSingleText(text, sourceLang, targetLang))
6664
+ );
6665
+ for (let j = 0; j < translated.length; j++) {
6666
+ results[start + j] = translated[j];
6667
+ }
6668
+ }
6669
+ return results;
6670
+ }
6671
+ function getTranslatableTextNodes() {
6672
+ const walker = document.createTreeWalker(
6673
+ document.body,
6674
+ NodeFilter.SHOW_TEXT,
6675
+ {
6676
+ acceptNode(node) {
6677
+ if (!node.textContent || !node.textContent.trim()) {
6678
+ return NodeFilter.FILTER_REJECT;
6679
+ }
6680
+ const parent = node.parentElement;
6681
+ if (!parent) return NodeFilter.FILTER_REJECT;
6682
+ const tag2 = parent.tagName;
6683
+ if (["SCRIPT", "STYLE", "NOSCRIPT", "CODE", "PRE", "TEXTAREA", "INPUT"].includes(tag2)) {
6684
+ return NodeFilter.FILTER_REJECT;
6685
+ }
6686
+ if (parent.closest("accessify-widget")) {
6687
+ return NodeFilter.FILTER_REJECT;
6688
+ }
6689
+ return NodeFilter.FILTER_ACCEPT;
6690
+ }
6691
+ }
6692
+ );
6693
+ const nodes = [];
6694
+ let current;
6695
+ while (current = walker.nextNode()) {
6696
+ nodes.push(current);
6697
+ }
6698
+ return nodes;
6699
+ }
6700
+ function createTextTransformService() {
6701
+ return {
6702
+ async translate(targetLang) {
6703
+ if (translating) return;
6704
+ translating = true;
6705
+ try {
6706
+ if (savedNodes.length > 0) {
6707
+ this.restore();
6708
+ }
6709
+ const pageLang = document.documentElement.lang?.split("-")[0] || "auto";
6710
+ const textNodes = getTranslatableTextNodes();
6711
+ if (textNodes.length === 0) {
6712
+ translating = false;
6713
+ return;
6714
+ }
6715
+ savedNodes = textNodes.map((node) => ({
6716
+ node,
6717
+ original: node.textContent
6718
+ }));
6719
+ const uniqueTexts = [...new Set(savedNodes.map((s) => s.original.trim()).filter(Boolean))];
6720
+ const translated = await translateTexts(uniqueTexts, pageLang, targetLang);
6721
+ const lookup = /* @__PURE__ */ new Map();
6722
+ uniqueTexts.forEach((text, i) => {
6723
+ if (translated[i]) {
6724
+ lookup.set(text, translated[i]);
6725
+ }
6726
+ });
6727
+ for (const saved of savedNodes) {
6728
+ const trimmed = saved.original.trim();
6729
+ const replacement = lookup.get(trimmed);
6730
+ if (replacement) {
6731
+ const leading = saved.original.match(/^\s*/)?.[0] || "";
6732
+ const trailing = saved.original.match(/\s*$/)?.[0] || "";
6733
+ saved.node.textContent = leading + replacement + trailing;
6734
+ }
6735
+ }
6736
+ currentTranslateLang = targetLang;
6737
+ } finally {
6738
+ translating = false;
6739
+ }
6740
+ },
6741
+ async simplify(_level, _lang) {
6742
+ },
6743
+ restore() {
6744
+ for (const saved of savedNodes) {
6745
+ saved.node.textContent = saved.original;
6746
+ }
6747
+ savedNodes = [];
6748
+ currentTranslateLang = null;
6749
+ },
6750
+ isTranslated() {
6751
+ return currentTranslateLang !== null;
6752
+ },
6753
+ currentLang() {
6754
+ return currentTranslateLang;
6755
+ }
6756
+ };
6757
+ }
6758
+ var root_3 = /* @__PURE__ */ from_svg(`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg>`);
6759
+ var root_2 = /* @__PURE__ */ from_html(`<button class="accessify-lang-option" role="option"><span> </span> <!></button>`);
6760
+ var root_1 = /* @__PURE__ */ from_html(`<div class="accessify-lang-list" role="listbox"></div>`);
6761
+ var root = /* @__PURE__ */ from_html(`<div class="sr-only" role="status" aria-live="polite" aria-atomic="true"> </div> <!> <div class="accessify-panel" role="dialog"><!> <div class="accessify-body"><div class="accessify-lang-dropdown"><button class="accessify-lang-toggle"><span class="accessify-lang-toggle-left"><!> <span> </span></span> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg></button> <!></div> <div class="accessify-section-divider"></div> <!> <div class="accessify-section-divider"></div> <!></div> <!></div>`, 1);
6762
+ function WidgetApp($$anchor, $$props) {
6763
+ push($$props, true);
6764
+ let config2 = prop($$props, "config", 7);
6765
+ let isOpen = /* @__PURE__ */ state(false);
6766
+ let activeFeatures = /* @__PURE__ */ state(proxy(/* @__PURE__ */ new Map()));
6767
+ let currentTheme = /* @__PURE__ */ state("light");
6768
+ let panelEl = /* @__PURE__ */ state(null);
6769
+ let triggerEl = /* @__PURE__ */ state(null);
6770
+ let announcement = /* @__PURE__ */ state("");
6771
+ let widgetLang = /* @__PURE__ */ state("en");
6772
+ let activeProfileId = /* @__PURE__ */ state(null);
6773
+ let langDropdownOpen = /* @__PURE__ */ state(false);
6774
+ const textTransformService = createTextTransformService();
6775
+ const STORAGE_KEY = "accessify-prefs";
6776
+ let activeCount = /* @__PURE__ */ user_derived(() => Array.from(get(activeFeatures).values()).filter(Boolean).length);
6777
+ let currentLangOption = /* @__PURE__ */ user_derived(() => LANGUAGE_OPTIONS.find((o) => o.code === get(widgetLang)));
6778
+ function announce(message) {
6779
+ set(announcement, "");
6780
+ requestAnimationFrame(() => {
6781
+ set(announcement, message, true);
6782
+ });
6783
+ }
6784
+ function loadPrefs() {
6785
+ try {
6786
+ const saved = localStorage.getItem(STORAGE_KEY);
6787
+ if (saved) {
6788
+ const prefs = JSON.parse(saved);
6789
+ set(activeFeatures, new Map(Object.entries(prefs)), true);
6790
+ }
6791
+ } catch {
6792
+ }
6793
+ }
6794
+ function savePrefs() {
6795
+ try {
6649
6796
  const obj = Object.fromEntries(get(activeFeatures));
6650
6797
  localStorage.setItem(STORAGE_KEY, JSON.stringify(obj));
6651
6798
  } catch {
@@ -6712,14 +6859,43 @@ function WidgetApp($$anchor, $$props) {
6712
6859
  }
6713
6860
  function resetAll() {
6714
6861
  set(activeFeatures, /* @__PURE__ */ new Map(), true);
6862
+ set(activeProfileId, null);
6715
6863
  savePrefs();
6864
+ textTransformService.restore();
6716
6865
  window.dispatchEvent(new CustomEvent("accessify:reset"));
6717
6866
  announce(t("widget.resetConfirm", get(widgetLang)));
6718
6867
  }
6868
+ function handleProfileActivate(profile) {
6869
+ if (get(activeProfileId) === profile.id) {
6870
+ set(activeProfileId, null);
6871
+ for (const fid of profile.features) {
6872
+ get(activeFeatures).set(fid, false);
6873
+ }
6874
+ set(activeFeatures, new Map(get(activeFeatures)), true);
6875
+ savePrefs();
6876
+ window.dispatchEvent(new CustomEvent("accessify:reset"));
6877
+ announce(`${t(profile.nameKey, get(widgetLang))} ${t("status.deactivated", get(widgetLang))}`);
6878
+ return;
6879
+ }
6880
+ set(activeProfileId, profile.id, true);
6881
+ for (const fid of profile.features) {
6882
+ get(activeFeatures).set(fid, true);
6883
+ }
6884
+ set(activeFeatures, new Map(get(activeFeatures)), true);
6885
+ savePrefs();
6886
+ announce(`${t(profile.nameKey, get(widgetLang))} ${t("status.activated", get(widgetLang))}`);
6887
+ }
6719
6888
  function handleLangChange(newLang) {
6720
6889
  set(widgetLang, getSupportedLang(newLang), true);
6721
6890
  config2().lang = get(widgetLang);
6891
+ set(langDropdownOpen, false);
6722
6892
  applyLanguage();
6893
+ const pageLang = document.documentElement.lang?.split("-")[0] || "en";
6894
+ if (get(widgetLang) !== pageLang) {
6895
+ textTransformService.translate(get(widgetLang));
6896
+ } else {
6897
+ textTransformService.restore();
6898
+ }
6723
6899
  }
6724
6900
  function handleKeydown(e) {
6725
6901
  if (e.key === "Escape" && get(isOpen)) {
@@ -6776,24 +6952,69 @@ function WidgetApp($$anchor, $$props) {
6776
6952
  get lang() {
6777
6953
  return get(widgetLang);
6778
6954
  },
6779
- onclose: close,
6780
- onreset: resetAll,
6781
- onlangchange: handleLangChange
6782
- });
6783
- var node_2 = sibling(node_1, 2);
6784
- StatusBar(node_2, {
6785
6955
  get activeCount() {
6786
6956
  return get(activeCount);
6787
6957
  },
6958
+ onclose: close,
6959
+ onreset: resetAll
6960
+ });
6961
+ var div_2 = sibling(node_1, 2);
6962
+ var div_3 = child(div_2);
6963
+ var button = child(div_3);
6964
+ var span = child(button);
6965
+ var node_2 = child(span);
6966
+ html(node_2, iconGlobe);
6967
+ var span_1 = sibling(node_2, 2);
6968
+ var text_1 = child(span_1);
6969
+ var svg = sibling(span, 2);
6970
+ let classes;
6971
+ var node_3 = sibling(button, 2);
6972
+ {
6973
+ var consequent_1 = ($$anchor2) => {
6974
+ var div_4 = root_1();
6975
+ each(div_4, 21, () => LANGUAGE_OPTIONS, index, ($$anchor3, option) => {
6976
+ var button_1 = root_2();
6977
+ var span_2 = child(button_1);
6978
+ var text_2 = child(span_2);
6979
+ var node_4 = sibling(span_2, 2);
6980
+ {
6981
+ var consequent = ($$anchor4) => {
6982
+ var svg_1 = root_3();
6983
+ append($$anchor4, svg_1);
6984
+ };
6985
+ if_block(node_4, ($$render) => {
6986
+ if (get(widgetLang) === get(option).code) $$render(consequent);
6987
+ });
6988
+ }
6989
+ template_effect(() => {
6990
+ set_attribute(button_1, "aria-selected", get(widgetLang) === get(option).code);
6991
+ set_attribute(button_1, "data-active", get(widgetLang) === get(option).code);
6992
+ set_text(text_2, `${(get(option).flag || "") ?? ""} ${get(option).label ?? ""}`);
6993
+ });
6994
+ delegated("click", button_1, () => handleLangChange(get(option).code));
6995
+ append($$anchor3, button_1);
6996
+ });
6997
+ template_effect(($0) => set_attribute(div_4, "aria-label", $0), [() => t("widget.widgetLang", get(widgetLang))]);
6998
+ append($$anchor2, div_4);
6999
+ };
7000
+ if_block(node_3, ($$render) => {
7001
+ if (get(langDropdownOpen)) $$render(consequent_1);
7002
+ });
7003
+ }
7004
+ var node_5 = sibling(div_3, 4);
7005
+ ProfileSection(node_5, {
6788
7006
  get lang() {
6789
7007
  return get(widgetLang);
6790
7008
  },
6791
- onreset: resetAll
7009
+ get activeProfileId() {
7010
+ return get(activeProfileId);
7011
+ },
7012
+ onactivate: handleProfileActivate
6792
7013
  });
6793
- var node_3 = sibling(node_2, 2);
7014
+ var node_6 = sibling(node_5, 4);
6794
7015
  {
6795
7016
  let $0 = /* @__PURE__ */ user_derived(() => ({ ...config2(), lang: get(widgetLang) }));
6796
- FeatureGrid(node_3, {
7017
+ FeatureGrid(node_6, {
6797
7018
  get config() {
6798
7019
  return get($0);
6799
7020
  },
@@ -6803,13 +7024,16 @@ function WidgetApp($$anchor, $$props) {
6803
7024
  ontoggle: handleFeatureToggle
6804
7025
  });
6805
7026
  }
6806
- var node_4 = sibling(node_3, 2);
6807
- PanelFooter(node_4, {
7027
+ var node_7 = sibling(div_2, 2);
7028
+ PanelFooter(node_7, {
6808
7029
  get lang() {
6809
7030
  return get(widgetLang);
6810
7031
  },
6811
7032
  get statementUrl() {
6812
7033
  return config2().statementUrl;
7034
+ },
7035
+ get dashboardUrl() {
7036
+ return config2().dashboardUrl;
6813
7037
  }
6814
7038
  });
6815
7039
  bind_this(div_1, ($$value) => set(panelEl, $$value), () => get(panelEl));
@@ -6819,6 +7043,9 @@ function WidgetApp($$anchor, $$props) {
6819
7043
  set_attribute(div_1, "aria-label", $0);
6820
7044
  set_attribute(div_1, "aria-hidden", !get(isOpen));
6821
7045
  set_attribute(div_1, "dir", $1);
7046
+ set_attribute(button, "aria-expanded", get(langDropdownOpen));
7047
+ set_text(text_1, `${(get(currentLangOption)?.flag || "") ?? ""} ${(get(currentLangOption)?.label || get(widgetLang)) ?? ""}`);
7048
+ classes = set_class(svg, 0, "accessify-lang-chevron", null, classes, { "accessify-lang-chevron--open": get(langDropdownOpen) });
6822
7049
  div_1.dir = div_1.dir;
6823
7050
  },
6824
7051
  [
@@ -6826,9 +7053,13 @@ function WidgetApp($$anchor, $$props) {
6826
7053
  () => isRtlLang(get(widgetLang)) ? "rtl" : "ltr"
6827
7054
  ]
6828
7055
  );
7056
+ delegated("click", button, () => {
7057
+ set(langDropdownOpen, !get(langDropdownOpen));
7058
+ });
6829
7059
  append($$anchor, fragment);
6830
7060
  return pop($$exports);
6831
7061
  }
7062
+ delegate(["click"]);
6832
7063
  const CHECKMARK_SVG = encodeURIComponent(
6833
7064
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>'
6834
7065
  );
@@ -6837,643 +7068,1125 @@ function createWidgetStyles(config2) {
6837
7068
  const isRight = pos.includes("right");
6838
7069
  const isBottom = pos.includes("bottom");
6839
7070
  const z = config2.zIndex || 999999;
6840
- const panelRadius = isRight ? "28px 0 0 28px" : "0 28px 28px 0";
7071
+ const panelRadius = isRight ? "20px 0 0 20px" : "0 20px 20px 0";
6841
7072
  const hiddenTransform = isRight ? "translateX(24px)" : "translateX(-24px)";
7073
+ const c = config2;
7074
+ const brandOverrides = [
7075
+ c.brandPrimaryColor ? `--surface: ${c.brandPrimaryColor};` : "",
7076
+ c.brandSurfaceColor ? `--surface-dim: ${c.brandSurfaceColor};` : "",
7077
+ c.brandCardColor ? `--surface-card: ${c.brandCardColor};` : "",
7078
+ c.brandHoverColor ? `--surface-hover: ${c.brandHoverColor};` : "",
7079
+ c.brandTextColor ? `--text: ${c.brandTextColor};` : "",
7080
+ c.brandTextDimColor ? `--text-dim: ${c.brandTextDimColor};` : "",
7081
+ c.brandAccentColor ? `--accent: ${c.brandAccentColor}; --accent-soft: ${c.brandAccentColor}26;` : "",
7082
+ c.brandBorderColor ? `--border: ${c.brandBorderColor}; --border-hl: ${c.brandBorderColor};` : ""
7083
+ ].filter(Boolean).join("\n ");
7084
+ const triggerBg = c.brandTriggerColor || "";
7085
+ const triggerIcon = c.brandTriggerIconColor || "";
7086
+ const panelW = c.panelWidth ? `${c.panelWidth}px` : "420px";
6842
7087
  return `
6843
7088
  :host {
6844
7089
  all: initial;
6845
7090
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
6846
7091
  font-size: 15px;
6847
7092
  line-height: 1.5;
6848
- color-scheme: light dark;
7093
+ color-scheme: dark;
6849
7094
  }
6850
7095
 
6851
- *, *::before, *::after {
6852
- box-sizing: border-box;
6853
- margin: 0;
6854
- padding: 0;
6855
- }
7096
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
6856
7097
 
6857
7098
  #accessify-mount {
6858
- --space-1: 4px;
6859
- --space-2: 8px;
6860
- --space-3: 12px;
6861
- --space-4: 16px;
6862
- --space-5: 20px;
6863
- --space-6: 24px;
6864
- --space-7: 32px;
6865
- --radius-sm: 12px;
6866
- --radius-md: 18px;
6867
- --radius-lg: 24px;
6868
- --radius-xl: 28px;
6869
- --radius-pill: 999px;
6870
- --text-xs: 12px;
6871
- --text-sm: 14px;
6872
- --text-base: 15px;
6873
- --text-lg: 18px;
6874
- --text-xl: 26px;
6875
- --font-medium: 500;
6876
- --font-semibold: 600;
6877
- --font-bold: 700;
6878
- --surface: #eff4f8;
6879
- --surface-strong: #ffffff;
6880
- --surface-muted: #f7f9fc;
6881
- --surface-tint: #ecf3fb;
6882
- --text: #152031;
6883
- --text-secondary: #5c6a79;
6884
- --border: rgba(21, 32, 49, 0.12);
6885
- --border-strong: rgba(21, 32, 49, 0.22);
6886
- --accent: #0e6bd8;
6887
- --accent-strong: #0a56a7;
6888
- --accent-soft: rgba(14, 107, 216, 0.1);
6889
- --text-on-accent: #ffffff;
6890
- --shadow-sm: 0 14px 32px rgba(15, 23, 42, 0.08);
6891
- --shadow-lg: 0 28px 72px rgba(15, 23, 42, 0.18);
6892
- --transition-fast: 160ms ease;
6893
- --transition-normal: 240ms ease;
7099
+ --gap: 14px;
7100
+ --pad: 18px;
7101
+ --radius: 12px;
7102
+ --radius-lg: 16px;
7103
+ --pill: 999px;
7104
+ --surface: #3d4775;
7105
+ --surface-card: #4a5387;
7106
+ --surface-dim: #353e6a;
7107
+ --surface-hover: #545d8f;
7108
+ --text: #f0f0f5;
7109
+ --text-dim: #b8bdd4;
7110
+ --border: rgba(255,255,255,0.10);
7111
+ --border-hl: rgba(255,255,255,0.20);
7112
+ --accent: #e8837c;
7113
+ --accent-soft: rgba(232,131,124,0.15);
7114
+ --accent-on: #fff;
7115
+ --shadow: 0 12px 48px rgba(0,0,0,0.35);
7116
+ --fast: 140ms ease;
7117
+ ${brandOverrides}
6894
7118
  }
6895
7119
 
6896
- @media (prefers-color-scheme: dark) {
6897
- #accessify-mount:not([data-theme="light"]) {
6898
- --surface: #101a27;
6899
- --surface-strong: #142233;
6900
- --surface-muted: #0f1825;
6901
- --surface-tint: #1a314c;
6902
- --text: #f5f8fb;
6903
- --text-secondary: #b3c0cd;
6904
- --border: rgba(245, 248, 251, 0.12);
6905
- --border-strong: rgba(245, 248, 251, 0.22);
6906
- --accent: #49a0ff;
6907
- --accent-strong: #1c7cde;
6908
- --accent-soft: rgba(73, 160, 255, 0.16);
6909
- --shadow-sm: 0 16px 36px rgba(0, 0, 0, 0.24);
6910
- --shadow-lg: 0 28px 80px rgba(0, 0, 0, 0.44);
6911
- }
6912
- }
6913
-
6914
- #accessify-mount[data-theme="dark"] {
6915
- --surface: #101a27;
6916
- --surface-strong: #142233;
6917
- --surface-muted: #0f1825;
6918
- --surface-tint: #1a314c;
6919
- --text: #f5f8fb;
6920
- --text-secondary: #b3c0cd;
6921
- --border: rgba(245, 248, 251, 0.12);
6922
- --border-strong: rgba(245, 248, 251, 0.22);
6923
- --accent: #49a0ff;
6924
- --accent-strong: #1c7cde;
6925
- --accent-soft: rgba(73, 160, 255, 0.16);
6926
- --shadow-sm: 0 16px 36px rgba(0, 0, 0, 0.24);
6927
- --shadow-lg: 0 28px 80px rgba(0, 0, 0, 0.44);
6928
- }
6929
-
6930
- .sr-only {
6931
- position: absolute;
6932
- width: 1px;
6933
- height: 1px;
6934
- padding: 0;
6935
- margin: -1px;
6936
- overflow: hidden;
6937
- clip: rect(0, 0, 0, 0);
6938
- white-space: nowrap;
6939
- border-width: 0;
6940
- }
6941
-
6942
- *:focus-visible {
6943
- outline: 3px solid var(--accent);
6944
- outline-offset: 3px;
6945
- border-radius: 12px;
6946
- }
7120
+ .sr-only { position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0; }
7121
+ *:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
6947
7122
 
7123
+ /* ─── Trigger ─── */
6948
7124
  .accessify-trigger {
6949
7125
  position: fixed;
6950
7126
  ${isBottom ? "bottom: 20px" : "top: 20px"};
6951
7127
  ${isRight ? "right: 20px" : "left: 20px"};
6952
7128
  z-index: ${z};
6953
- width: 60px;
6954
- height: 60px;
6955
- border: none;
6956
- border-radius: 20px;
6957
- background: linear-gradient(180deg, #1681f2 0%, #0e6bd8 100%);
6958
- color: #ffffff;
7129
+ width: 56px; height: 56px;
7130
+ border: none; border-radius: 16px;
7131
+ background: ${triggerBg || "linear-gradient(135deg, #545d8f, #3d4775)"};
7132
+ color: ${triggerIcon || "#e8837c"};
6959
7133
  cursor: pointer;
6960
- display: flex;
6961
- align-items: center;
6962
- justify-content: center;
6963
- box-shadow: 0 18px 36px rgba(14, 107, 216, 0.28);
6964
- transition: transform var(--transition-fast), box-shadow var(--transition-fast), opacity var(--transition-fast);
6965
- }
6966
-
6967
- .accessify-trigger:hover {
6968
- transform: translateY(-1px);
6969
- box-shadow: 0 20px 40px rgba(14, 107, 216, 0.32);
6970
- }
6971
-
6972
- .accessify-trigger:active {
6973
- transform: scale(0.98);
6974
- }
6975
-
6976
- .accessify-trigger[aria-expanded="true"] {
6977
- opacity: 0;
6978
- pointer-events: none;
6979
- transform: scale(0.92);
6980
- }
6981
-
6982
- .accessify-trigger svg {
6983
- width: 28px;
6984
- height: 28px;
6985
- }
7134
+ display: flex; align-items: center; justify-content: center;
7135
+ box-shadow: 0 6px 20px rgba(50,60,100,0.5);
7136
+ transition: transform var(--fast), box-shadow var(--fast), opacity var(--fast);
7137
+ touch-action: none;
7138
+ }
7139
+ .accessify-trigger:hover { transform: translateY(-2px); box-shadow: 0 8px 28px rgba(50,60,100,0.6); }
7140
+ .accessify-trigger:active { transform: scale(0.96); }
7141
+ .accessify-trigger[aria-expanded="true"] { opacity:0; pointer-events:none; transform:scale(0.9); }
7142
+ .accessify-trigger svg { width: 26px; height: 26px; }
7143
+ .accessify-trigger--dragging { cursor: grabbing !important; opacity: 0.85; }
6986
7144
 
7145
+ /* ─── Panel ─── */
6987
7146
  .accessify-panel {
6988
- position: fixed;
6989
- top: 0;
6990
- bottom: 0;
7147
+ position: fixed; top: 0; bottom: 0;
6991
7148
  ${isRight ? "right: 0" : "left: 0"};
6992
7149
  z-index: ${z - 1};
6993
- width: min(440px, 100vw);
6994
- height: 100vh;
6995
- display: flex;
6996
- flex-direction: column;
6997
- overflow: hidden;
7150
+ width: min(${panelW}, 100vw); height: 100vh;
7151
+ display: flex; flex-direction: column;
6998
7152
  border-radius: ${panelRadius};
6999
- ${isRight ? "border-left" : "border-right"}: 1px solid var(--border);
7000
- background: linear-gradient(180deg, var(--surface-strong) 0%, var(--surface) 100%);
7153
+ background: var(--surface);
7001
7154
  color: var(--text);
7002
- box-shadow: var(--shadow-lg);
7003
- transition: opacity var(--transition-normal), transform var(--transition-normal);
7004
- }
7005
-
7006
- .accessify-panel[aria-hidden="true"] {
7007
- opacity: 0;
7008
- transform: ${hiddenTransform};
7009
- pointer-events: none;
7010
- display: none;
7011
- }
7012
-
7013
- .accessify-panel[aria-hidden="false"] {
7014
- opacity: 1;
7015
- transform: translateX(0);
7155
+ box-shadow: var(--shadow);
7156
+ transition: opacity 200ms ease, transform 200ms ease;
7016
7157
  }
7158
+ .accessify-panel[aria-hidden="true"] { opacity:0; transform:${hiddenTransform}; pointer-events:none; display:none; }
7159
+ .accessify-panel[aria-hidden="false"] { opacity:1; transform:translateX(0); }
7017
7160
 
7161
+ /* ─── Header ─── */
7018
7162
  .accessify-header {
7019
- position: sticky;
7020
- top: 0;
7021
- z-index: 1;
7022
- display: grid;
7023
- gap: var(--space-4);
7024
- padding: var(--space-6) var(--space-6) var(--space-5);
7163
+ display: flex; align-items: center; justify-content: space-between;
7164
+ padding: 14px var(--pad);
7025
7165
  border-bottom: 1px solid var(--border);
7026
- background: color-mix(in srgb, var(--surface-strong) 94%, transparent);
7027
- backdrop-filter: blur(16px);
7028
- }
7029
-
7030
- .accessify-header-top {
7031
- display: flex;
7032
- align-items: flex-start;
7033
- justify-content: space-between;
7034
- gap: var(--space-4);
7035
- }
7036
-
7037
- .accessify-header-title {
7038
- display: grid;
7039
- gap: 6px;
7040
- }
7041
-
7042
- .accessify-header h2 {
7043
- font-size: var(--text-xl);
7044
- font-weight: var(--font-bold);
7045
- line-height: 1.08;
7046
- letter-spacing: -0.02em;
7047
- color: var(--text);
7166
+ background: var(--surface-dim);
7167
+ flex-shrink: 0;
7048
7168
  }
7169
+ .accessify-header-left { display: flex; align-items: center; gap: 10px; }
7170
+ .accessify-header-actions { display: flex; align-items: center; gap: 6px; }
7049
7171
 
7050
- .accessify-header p {
7051
- color: var(--text-secondary);
7052
- font-size: var(--text-sm);
7053
- max-width: 34ch;
7054
- }
7172
+ .accessify-logo { display: inline-flex; color: var(--accent); }
7173
+ .accessify-logo svg { height: 24px; width: auto; }
7055
7174
 
7056
- .accessify-header-toolbar {
7057
- display: grid;
7058
- grid-template-columns: minmax(0, 1fr) auto;
7059
- align-items: center;
7060
- gap: var(--space-3);
7061
- }
7175
+ .accessify-header-btn {
7176
+ display: inline-flex; align-items: center; justify-content: center;
7177
+ width: 34px; height: 34px;
7178
+ border: 1px solid var(--border); border-radius: 10px;
7179
+ background: var(--surface); color: var(--text-dim);
7180
+ cursor: pointer; transition: background var(--fast), color var(--fast);
7181
+ }
7182
+ .accessify-header-btn:hover { background: var(--surface-hover); color: var(--text); }
7183
+ .accessify-header-btn svg { width: 16px; height: 16px; }
7184
+ .accessify-header-btn--icon { padding: 0; }
7185
+ .accessify-header-btn--close { background: transparent; border-color: transparent; }
7062
7186
 
7063
- .accessify-language-picker {
7064
- position: relative;
7065
- display: inline-flex;
7066
- align-items: center;
7067
- gap: 10px;
7068
- min-width: 0;
7069
- min-height: 48px;
7070
- padding: 0 14px;
7071
- border-radius: 16px;
7187
+ /* ─── Shared Accordion (Language + Profiles) ─── */
7188
+ .accessify-lang-dropdown,
7189
+ .accessify-accordion {
7190
+ border-radius: var(--radius);
7072
7191
  border: 1px solid var(--border);
7073
- background: var(--surface-strong);
7074
- color: var(--text);
7192
+ overflow: clip;
7075
7193
  }
7076
7194
 
7077
- .accessify-language-icon {
7078
- display: inline-flex;
7079
- align-items: center;
7080
- justify-content: center;
7081
- color: var(--accent-strong);
7082
- flex-shrink: 0;
7083
- }
7195
+ .accessify-lang-toggle,
7196
+ .accessify-accordion-toggle {
7197
+ display: flex; align-items: center; justify-content: space-between;
7198
+ width: 100%; padding: 14px 14px;
7199
+ border: none; background: var(--surface-card);
7200
+ color: var(--text); cursor: pointer; font-family: inherit;
7201
+ font-size: 15px; font-weight: 700;
7202
+ transition: background var(--fast);
7203
+ }
7204
+ .accessify-lang-toggle:hover,
7205
+ .accessify-accordion-toggle:hover { background: var(--surface-hover); }
7084
7206
 
7085
- .accessify-language-icon svg {
7086
- width: 16px;
7087
- height: 16px;
7207
+ .accessify-lang-toggle-left,
7208
+ .accessify-accordion-toggle-left {
7209
+ display: flex; align-items: center; gap: 10px;
7088
7210
  }
7211
+ .accessify-lang-toggle-left svg,
7212
+ .accessify-accordion-toggle-left svg { width: 20px; height: 20px; color: var(--accent); }
7089
7213
 
7090
- .accessify-language-select {
7091
- appearance: none;
7092
- width: 100%;
7093
- border: none;
7094
- background: transparent;
7095
- color: var(--text);
7096
- padding: 12px 0;
7097
- font-size: var(--text-sm);
7098
- font-weight: var(--font-medium);
7099
- cursor: pointer;
7100
- min-width: 0;
7101
- }
7102
-
7103
- .accessify-language-select option {
7104
- color: #152031;
7214
+ .accessify-lang-chevron,
7215
+ .accessify-accordion-chevron {
7216
+ width: 18px; height: 18px; color: var(--text-dim);
7217
+ transition: transform 200ms ease; flex-shrink: 0;
7105
7218
  }
7219
+ .accessify-lang-chevron--open,
7220
+ .accessify-accordion-chevron--open { transform: rotate(180deg); }
7106
7221
 
7107
- .accessify-header-btn {
7108
- display: inline-flex;
7109
- align-items: center;
7110
- justify-content: center;
7111
- gap: 8px;
7112
- min-height: 48px;
7113
- padding: 0 16px;
7114
- border: 1px solid var(--border);
7115
- border-radius: 16px;
7116
- background: var(--surface-strong);
7117
- color: var(--text);
7118
- cursor: pointer;
7119
- font-size: var(--text-sm);
7120
- font-weight: var(--font-semibold);
7121
- transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
7122
- }
7123
-
7124
- .accessify-header-btn:hover {
7125
- background: var(--surface-muted);
7126
- border-color: var(--border-strong);
7127
- transform: translateY(-1px);
7222
+ /* Shared list inside accordion */
7223
+ .accessify-lang-list,
7224
+ .accessify-accordion-list {
7225
+ display: flex; flex-direction: column;
7226
+ max-height: 280px; overflow-y: auto;
7227
+ background: var(--surface-dim);
7228
+ border-top: 1px solid var(--border);
7128
7229
  }
7230
+ .accessify-lang-list::-webkit-scrollbar,
7231
+ .accessify-accordion-list::-webkit-scrollbar { width: 4px; }
7232
+ .accessify-lang-list::-webkit-scrollbar-thumb,
7233
+ .accessify-accordion-list::-webkit-scrollbar-thumb { background: var(--border-hl); border-radius: 2px; }
7129
7234
 
7130
- .accessify-header-btn--secondary {
7131
- background: var(--surface-muted);
7132
- }
7235
+ /* Language options */
7236
+ .accessify-lang-option {
7237
+ display: flex; align-items: center; justify-content: space-between;
7238
+ padding: 12px var(--pad);
7239
+ border: none; background: transparent;
7240
+ color: var(--text); cursor: pointer;
7241
+ font-size: 14px; font-weight: 500; font-family: inherit;
7242
+ transition: background var(--fast);
7243
+ }
7244
+ .accessify-lang-option:hover { background: var(--surface-hover); }
7245
+ .accessify-lang-option[data-active="true"] { color: var(--accent); font-weight: 700; }
7246
+ .accessify-lang-option svg { width: 18px; height: 18px; color: var(--accent); flex-shrink: 0; }
7133
7247
 
7134
- .accessify-header-btn svg {
7135
- width: 16px;
7136
- height: 16px;
7137
- }
7248
+ /* Profile options (with icon + description) */
7249
+ .accessify-accordion-option {
7250
+ display: flex; align-items: center; justify-content: space-between;
7251
+ padding: 14px var(--pad);
7252
+ border: none; background: transparent;
7253
+ color: var(--text); cursor: pointer;
7254
+ font-family: inherit; text-align: left;
7255
+ transition: background var(--fast);
7256
+ }
7257
+ .accessify-accordion-option:hover { background: var(--surface-hover); }
7258
+ .accessify-accordion-option[data-active="true"] { background: var(--accent-soft); }
7138
7259
 
7139
- .accessify-header-btn--icon {
7140
- width: 48px;
7141
- min-width: 48px;
7142
- padding-inline: 0;
7143
- flex-shrink: 0;
7260
+ .accessify-accordion-option-left {
7261
+ display: flex; align-items: center; gap: 12px; min-width: 0;
7144
7262
  }
7145
-
7146
- .accessify-status {
7147
- display: flex;
7148
- align-items: center;
7149
- justify-content: space-between;
7150
- gap: var(--space-3);
7151
- padding: 14px var(--space-6);
7152
- border-bottom: 1px solid var(--border);
7153
- background: linear-gradient(180deg, var(--accent-soft) 0%, transparent 100%);
7263
+ .accessify-accordion-option-icon {
7264
+ display: inline-flex; align-items: center; justify-content: center;
7265
+ width: 40px; height: 40px; border-radius: 12px;
7266
+ background: var(--surface-card); color: var(--accent); flex-shrink: 0;
7154
7267
  }
7155
-
7156
- .accessify-status-count {
7157
- display: inline-flex;
7158
- align-items: center;
7159
- gap: 8px;
7160
- min-height: 36px;
7161
- padding: 0 14px;
7162
- border-radius: var(--radius-pill);
7163
- background: var(--accent-soft);
7164
- color: var(--accent-strong);
7165
- font-size: var(--text-sm);
7166
- font-weight: var(--font-semibold);
7268
+ .accessify-accordion-option-icon svg { width: 24px; height: 24px; stroke-width: 2.5; }
7269
+ .accessify-accordion-option-text {
7270
+ display: flex; flex-direction: column; gap: 2px; min-width: 0;
7167
7271
  }
7168
-
7169
- .accessify-status-count[data-count="0"] {
7170
- background: var(--surface-muted);
7171
- color: var(--text-secondary);
7272
+ .accessify-accordion-option-name {
7273
+ font-size: 14px; font-weight: 700; line-height: 1.3;
7172
7274
  }
7173
-
7174
- .accessify-status-reset {
7175
- border: none;
7176
- background: none;
7177
- color: var(--text-secondary);
7178
- cursor: pointer;
7179
- font-size: var(--text-sm);
7180
- font-weight: var(--font-medium);
7181
- padding: 8px 0;
7182
- transition: color var(--transition-fast);
7275
+ .accessify-accordion-option-desc {
7276
+ font-size: 12px; font-weight: 400; color: var(--text-dim); line-height: 1.3;
7183
7277
  }
7184
-
7185
- .accessify-status-reset:hover {
7186
- color: var(--accent-strong);
7278
+ .accessify-accordion-option > svg {
7279
+ width: 20px; height: 20px; color: var(--accent); flex-shrink: 0; margin-left: 8px;
7187
7280
  }
7188
7281
 
7282
+ /* ─── Scrollable Body ─── */
7189
7283
  .accessify-body {
7190
7284
  flex: 1 1 auto;
7191
- display: grid;
7192
- gap: var(--space-4);
7193
- padding: var(--space-4);
7194
- overflow-y: auto;
7195
- overscroll-behavior: contain;
7196
- background: var(--surface);
7285
+ display: flex; flex-direction: column; gap: var(--gap);
7286
+ padding: var(--gap) var(--pad);
7287
+ overflow-y: auto; overscroll-behavior: contain;
7197
7288
  }
7198
7289
 
7199
- .accessify-section {
7200
- display: grid;
7201
- gap: var(--space-4);
7202
- padding: var(--space-5);
7203
- border-radius: var(--radius-xl);
7204
- border: 1px solid var(--border);
7205
- background: var(--surface-strong);
7206
- box-shadow: var(--shadow-sm);
7207
- }
7290
+ /* ─── Contrast Row ─── */
7291
+ .accessify-control-row {
7292
+ display: flex; flex-direction: column; gap: 10px;
7293
+ padding: 14px 16px;
7294
+ border-radius: var(--radius); border: 1px solid var(--border);
7295
+ background: var(--surface-card);
7296
+ }
7297
+ .accessify-control-label {
7298
+ display: flex; align-items: center; gap: 8px;
7299
+ }
7300
+ .accessify-control-label-icon {
7301
+ display: inline-flex; align-items: center; justify-content: center;
7302
+ width: 34px; height: 34px; border-radius: 10px;
7303
+ background: var(--surface-dim); color: var(--accent); flex-shrink: 0;
7304
+ }
7305
+ .accessify-control-label-icon svg { width: 18px; height: 18px; }
7306
+ .accessify-control-label-text { font-size: 14px; font-weight: 600; }
7208
7307
 
7209
- .accessify-section--priority {
7210
- background: linear-gradient(180deg, var(--surface-strong) 0%, var(--surface-muted) 100%);
7211
- }
7212
-
7213
- .accessify-section-head {
7214
- display: grid;
7215
- gap: 6px;
7216
- }
7217
-
7218
- .accessify-section-head h3 {
7219
- font-size: var(--text-lg);
7220
- font-weight: var(--font-bold);
7221
- line-height: 1.15;
7222
- color: var(--text);
7223
- }
7224
-
7225
- .accessify-section-head p {
7226
- color: var(--text-secondary);
7227
- font-size: var(--text-sm);
7228
- line-height: 1.45;
7229
- max-width: 46ch;
7230
- }
7231
-
7232
- .accessify-control-grid {
7233
- display: grid;
7234
- grid-template-columns: repeat(2, minmax(0, 1fr));
7235
- gap: var(--space-3);
7236
- }
7237
-
7238
- .accessify-control-card {
7239
- display: grid;
7240
- gap: var(--space-4);
7241
- min-height: 176px;
7242
- padding: var(--space-4);
7243
- border-radius: 22px;
7244
- border: 1px solid var(--border);
7245
- background: var(--surface-muted);
7308
+ /* Contrast chips */
7309
+ .accessify-chip-row {
7310
+ display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
7246
7311
  }
7312
+ .accessify-chip {
7313
+ min-height: 48px; padding: 6px 8px;
7314
+ border-radius: 10px; border: 1px solid var(--border);
7315
+ background: var(--surface-dim); color: var(--text);
7316
+ cursor: pointer; font-size: 11px; font-weight: 600; font-family: inherit;
7317
+ display: inline-flex; align-items: center; justify-content: center;
7318
+ text-align: center; line-height: 1.25;
7319
+ transition: background var(--fast), color var(--fast), border-color var(--fast);
7320
+ }
7321
+ .accessify-chip:hover { border-color: var(--border-hl); background: var(--surface-hover); }
7322
+ .accessify-chip[data-active="true"] { background: var(--accent); color: var(--accent-on); border-color: var(--accent); }
7323
+ .accessify-chip--icon { gap: 6px; }
7324
+ .accessify-chip-icon { display: inline-flex; width: 14px; height: 14px; flex-shrink: 0; }
7325
+ .accessify-chip-icon svg { width: 14px; height: 14px; }
7247
7326
 
7248
- .accessify-control-copy {
7249
- display: grid;
7250
- grid-template-columns: auto 1fr;
7251
- gap: var(--space-3);
7252
- align-items: start;
7327
+ /* Text Size stepper */
7328
+ .accessify-control-row:has(.accessify-stepper) {
7329
+ flex-direction: row; align-items: center; justify-content: space-between; gap: var(--gap);
7330
+ }
7331
+ .accessify-stepper {
7332
+ display: inline-flex; align-items: center;
7333
+ border-radius: 10px; border: 1px solid var(--border);
7334
+ background: var(--surface-dim); height: 36px; overflow: hidden;
7335
+ }
7336
+ .accessify-stepper-btn {
7337
+ display: inline-flex; align-items: center; justify-content: center;
7338
+ width: 36px; height: 100%; border: none; background: transparent;
7339
+ color: var(--text); cursor: pointer; font-size: 18px; font-weight: 700;
7340
+ transition: background var(--fast); font-family: inherit;
7341
+ }
7342
+ .accessify-stepper-btn:hover:not(:disabled) { background: var(--surface-hover); }
7343
+ .accessify-stepper-btn:disabled { opacity: 0.3; cursor: default; }
7344
+ .accessify-stepper-value {
7345
+ min-width: 48px; text-align: center;
7346
+ font-size: 13px; font-weight: 600; color: var(--text); user-select: none;
7253
7347
  }
7254
7348
 
7255
- .accessify-control-copy h4 {
7256
- font-size: var(--text-base);
7257
- font-weight: var(--font-bold);
7258
- color: var(--text);
7349
+ /* ─── Feature Cards (2-column grid) ─── */
7350
+ .accessify-features {
7351
+ display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap);
7259
7352
  }
7260
-
7261
- .accessify-control-copy p {
7262
- margin-top: 4px;
7263
- color: var(--text-secondary);
7264
- font-size: var(--text-sm);
7265
- line-height: 1.45;
7353
+ .accessify-card-wrap {
7354
+ position: relative;
7355
+ overflow: visible;
7266
7356
  }
7267
-
7268
- .accessify-chip-group {
7269
- display: flex;
7270
- flex-wrap: wrap;
7271
- gap: 10px;
7357
+ .accessify-card {
7358
+ position: relative; width: 100%;
7359
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
7360
+ gap: 8px; padding: 18px 10px; min-height: 105px;
7361
+ border-radius: var(--radius-lg); border: 1px solid var(--border);
7362
+ background: var(--surface-card); color: var(--text);
7363
+ cursor: pointer; text-align: center; font-family: inherit;
7364
+ transition: transform var(--fast), border-color var(--fast), background var(--fast), box-shadow var(--fast);
7365
+ }
7366
+ .accessify-card:hover { transform: translateY(-2px); border-color: var(--border-hl); box-shadow: 0 4px 16px rgba(0,0,0,0.15); }
7367
+ .accessify-card[data-active="true"] { border-color: var(--accent); background: var(--accent-soft); }
7368
+ .accessify-card[data-active="true"]::after {
7369
+ content: ''; position: absolute; top: 8px; ${isRight ? "right: 8px" : "left: 8px"};
7370
+ width: 18px; height: 18px; border-radius: 999px; background: var(--accent);
7371
+ mask-image: url("data:image/svg+xml,${CHECKMARK_SVG}");
7372
+ mask-size: 10px; mask-repeat: no-repeat; mask-position: center;
7373
+ -webkit-mask-image: url("data:image/svg+xml,${CHECKMARK_SVG}");
7374
+ -webkit-mask-size: 10px; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center;
7272
7375
  }
7273
-
7274
- .accessify-chip {
7275
- min-height: 42px;
7276
- padding: 0 14px;
7277
- border-radius: 16px;
7278
- border: 1px solid var(--border);
7279
- background: var(--surface-strong);
7280
- color: var(--text);
7281
- cursor: pointer;
7282
- font-size: var(--text-sm);
7283
- font-weight: var(--font-semibold);
7284
- display: inline-flex;
7285
- align-items: center;
7286
- justify-content: center;
7287
- transition: transform var(--transition-fast), background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
7376
+ .accessify-card-icon {
7377
+ display: inline-flex; align-items: center; justify-content: center;
7378
+ width: 48px; height: 48px; border-radius: 14px;
7379
+ background: var(--surface-dim); color: var(--accent);
7288
7380
  }
7381
+ .accessify-card-icon svg { width: 28px; height: 28px; stroke-width: 2.5; }
7382
+ .accessify-card-label { font-size: 12px; font-weight: 600; line-height: 1.25; }
7289
7383
 
7290
- .accessify-chip:hover {
7291
- transform: translateY(-1px);
7292
- border-color: var(--border-strong);
7293
- background: var(--surface);
7384
+ /* Info icon + tooltip */
7385
+ .accessify-card-info {
7386
+ position: absolute; top: 6px; ${isRight ? "right: 6px" : "left: 6px"}; z-index: 10;
7387
+ display: inline-flex; align-items: center; justify-content: center;
7388
+ width: 22px; height: 22px; border-radius: 999px;
7389
+ color: var(--text-dim); cursor: help; background: none; border: none;
7390
+ opacity: 0.35; transition: opacity var(--fast), color var(--fast);
7391
+ }
7392
+ .accessify-card-info svg { width: 14px; height: 14px; }
7393
+ .accessify-card-info:hover, .accessify-card-info:focus-visible { opacity: 1; color: var(--accent); }
7394
+ .accessify-card-tooltip {
7395
+ display: none; position: absolute;
7396
+ top: calc(100% + 6px); ${isRight ? "right: 0" : "left: 0"};
7397
+ width: 180px; padding: 10px 12px;
7398
+ border-radius: 10px; background: #2a3158; color: var(--text);
7399
+ font-size: 12px; font-weight: 500; line-height: 1.4;
7400
+ text-align: left; white-space: normal;
7401
+ box-shadow: 0 6px 24px rgba(0,0,0,0.5);
7402
+ pointer-events: none; z-index: 100;
7403
+ }
7404
+ .accessify-card-info:hover .accessify-card-tooltip,
7405
+ .accessify-card-info:focus-visible .accessify-card-tooltip {
7406
+ display: block;
7407
+ }
7408
+ .accessify-card-tooltip::before {
7409
+ content: ''; position: absolute; bottom: 100%; ${isRight ? "right: 4px" : "left: 4px"};
7410
+ border: 5px solid transparent; border-bottom-color: #2a3158;
7294
7411
  }
7295
7412
 
7296
- .accessify-chip[data-active="true"] {
7297
- background: linear-gradient(180deg, var(--accent) 0%, var(--accent-strong) 100%);
7298
- color: var(--text-on-accent);
7299
- border-color: var(--accent);
7300
- box-shadow: 0 12px 20px rgba(14, 107, 216, 0.2);
7413
+ /* ─── Section Divider ─── */
7414
+ .accessify-section-divider {
7415
+ height: 1px;
7416
+ background: var(--border);
7417
+ margin: 4px 0;
7418
+ flex-shrink: 0;
7301
7419
  }
7302
7420
 
7303
- .accessify-chip-group--sizes .accessify-chip {
7304
- min-width: 68px;
7421
+ /* ─── Footer ─── */
7422
+ .accessify-footer {
7423
+ display: flex; align-items: center; justify-content: center; gap: 8px;
7424
+ padding: 8px var(--pad);
7425
+ border-top: 1px solid var(--border);
7426
+ color: var(--text-dim); font-size: 11px;
7427
+ background: var(--surface-dim); flex-shrink: 0;
7305
7428
  }
7429
+ .accessify-footer a { color: var(--accent); text-decoration: none; font-weight: 600; }
7430
+ .accessify-footer a:hover { text-decoration: underline; }
7306
7431
 
7307
- .accessify-features {
7308
- display: grid;
7309
- grid-template-columns: repeat(2, minmax(0, 1fr));
7310
- gap: var(--space-3);
7432
+ /* ─── Reduced Motion ─── */
7433
+ @media (prefers-reduced-motion: reduce) {
7434
+ *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
7311
7435
  }
7312
7436
 
7313
- .accessify-card {
7314
- position: relative;
7315
- display: grid;
7316
- align-content: start;
7317
- gap: 12px;
7318
- min-height: 164px;
7319
- padding: var(--space-4);
7320
- border-radius: 24px;
7321
- border: 1px solid var(--border);
7322
- background: var(--surface-strong);
7323
- color: var(--text);
7324
- cursor: pointer;
7325
- text-align: left;
7326
- font-family: inherit;
7327
- font-size: inherit;
7328
- transition: transform var(--transition-fast), border-color var(--transition-fast), background var(--transition-fast), box-shadow var(--transition-fast);
7437
+ /* ─── Mobile ─── */
7438
+ @media (max-width: 640px) {
7439
+ .accessify-panel { width: 100vw; border-radius: 0; }
7440
+ .accessify-features { gap: 8px; }
7441
+ .accessify-body { padding: 8px 12px; }
7442
+ .accessify-trigger {
7443
+ ${isBottom ? "bottom: 16px" : "top: 16px"};
7444
+ ${isRight ? "right: 16px" : "left: 16px"};
7445
+ width: 50px; height: 50px; border-radius: 14px;
7446
+ }
7329
7447
  }
7330
-
7331
- .accessify-card:hover {
7332
- transform: translateY(-2px);
7333
- border-color: color-mix(in srgb, var(--accent) 28%, var(--border));
7334
- box-shadow: var(--shadow-sm);
7448
+ `;
7449
+ }
7450
+ const IDB_NAME = "accessify-alt-text-cache";
7451
+ const IDB_STORE = "alt-texts";
7452
+ const IDB_REPORT_STORE = "alt-text-reports";
7453
+ const IDB_VERSION = 2;
7454
+ function hashSrc(src) {
7455
+ let hash = 5381;
7456
+ const n = src.toLowerCase().trim();
7457
+ for (let i = 0; i < n.length; i++) {
7458
+ hash = (hash << 5) + hash + n.charCodeAt(i);
7459
+ hash |= 0;
7460
+ }
7461
+ return Math.abs(hash).toString(36);
7462
+ }
7463
+ function openCache() {
7464
+ return new Promise((resolve) => {
7465
+ try {
7466
+ const req = indexedDB.open(IDB_NAME, IDB_VERSION);
7467
+ req.onupgradeneeded = () => {
7468
+ const db = req.result;
7469
+ if (!db.objectStoreNames.contains(IDB_STORE)) db.createObjectStore(IDB_STORE, { keyPath: "key" });
7470
+ if (!db.objectStoreNames.contains(IDB_REPORT_STORE)) db.createObjectStore(IDB_REPORT_STORE, { keyPath: "key" });
7471
+ };
7472
+ req.onsuccess = () => resolve(req.result);
7473
+ req.onerror = () => resolve(null);
7474
+ } catch {
7475
+ resolve(null);
7335
7476
  }
7336
-
7337
- .accessify-card[data-active="true"] {
7338
- border-color: color-mix(in srgb, var(--accent) 48%, var(--border));
7339
- background: linear-gradient(180deg, var(--accent-soft) 0%, var(--surface-strong) 100%);
7340
- box-shadow: 0 16px 30px rgba(14, 107, 216, 0.12);
7477
+ });
7478
+ }
7479
+ async function getAllCachedAltTexts() {
7480
+ const db = await openCache();
7481
+ const map = /* @__PURE__ */ new Map();
7482
+ if (!db) return map;
7483
+ return new Promise((resolve) => {
7484
+ try {
7485
+ const tx = db.transaction(IDB_STORE, "readonly");
7486
+ const req = tx.objectStore(IDB_STORE).getAll();
7487
+ req.onsuccess = () => {
7488
+ const results = req.result;
7489
+ for (const r of results) {
7490
+ map.set(r.src, r.altText);
7491
+ }
7492
+ resolve(map);
7493
+ };
7494
+ req.onerror = () => resolve(map);
7495
+ } catch {
7496
+ resolve(map);
7341
7497
  }
7342
-
7343
- .accessify-card[data-active="true"]::after {
7344
- content: '';
7345
- position: absolute;
7346
- top: 14px;
7347
- right: 14px;
7348
- width: 22px;
7349
- height: 22px;
7350
- border-radius: 999px;
7351
- background: var(--accent);
7352
- mask-image: url("data:image/svg+xml,${CHECKMARK_SVG}");
7353
- mask-size: 12px;
7354
- mask-repeat: no-repeat;
7355
- mask-position: center;
7356
- -webkit-mask-image: url("data:image/svg+xml,${CHECKMARK_SVG}");
7357
- -webkit-mask-size: 12px;
7358
- -webkit-mask-repeat: no-repeat;
7359
- -webkit-mask-position: center;
7498
+ });
7499
+ }
7500
+ async function getCachedAltText(src) {
7501
+ const db = await openCache();
7502
+ if (!db) return null;
7503
+ return new Promise((resolve) => {
7504
+ try {
7505
+ const tx = db.transaction(IDB_STORE, "readonly");
7506
+ const req = tx.objectStore(IDB_STORE).get(hashSrc(src));
7507
+ req.onsuccess = () => resolve(req.result?.altText || null);
7508
+ req.onerror = () => resolve(null);
7509
+ } catch {
7510
+ resolve(null);
7360
7511
  }
7361
-
7362
- .accessify-card-top {
7363
- display: flex;
7364
- align-items: center;
7365
- justify-content: space-between;
7366
- gap: var(--space-2);
7512
+ });
7513
+ }
7514
+ async function setCachedAltText(src, altText2, langCode) {
7515
+ const db = await openCache();
7516
+ if (!db) return;
7517
+ return new Promise((resolve) => {
7518
+ try {
7519
+ const tx = db.transaction(IDB_STORE, "readwrite");
7520
+ tx.objectStore(IDB_STORE).put({ key: hashSrc(src), src, altText: altText2, lang: langCode, createdAt: Date.now() });
7521
+ tx.oncomplete = () => resolve();
7522
+ tx.onerror = () => resolve();
7523
+ } catch {
7524
+ resolve();
7367
7525
  }
7368
-
7369
- .accessify-card-icon {
7370
- display: inline-flex;
7371
- align-items: center;
7372
- justify-content: center;
7373
- width: 52px;
7374
- height: 52px;
7375
- border-radius: 18px;
7376
- background: var(--surface-tint);
7377
- color: var(--accent-strong);
7378
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
7526
+ });
7527
+ }
7528
+ async function saveReport(src, altText2, langCode) {
7529
+ const db = await openCache();
7530
+ if (!db) return;
7531
+ return new Promise((resolve) => {
7532
+ try {
7533
+ const tx = db.transaction(IDB_REPORT_STORE, "readwrite");
7534
+ tx.objectStore(IDB_REPORT_STORE).put({
7535
+ key: hashSrc(src) + "_" + Date.now(),
7536
+ src,
7537
+ pageUrl: window.location.href,
7538
+ altText: altText2,
7539
+ lang: langCode,
7540
+ reportedAt: Date.now()
7541
+ });
7542
+ tx.oncomplete = () => resolve();
7543
+ tx.onerror = () => resolve();
7544
+ } catch {
7545
+ resolve();
7379
7546
  }
7380
-
7381
- .accessify-card-icon svg {
7382
- width: 22px;
7383
- height: 22px;
7547
+ });
7548
+ }
7549
+ async function removeCachedAltText(src) {
7550
+ const db = await openCache();
7551
+ if (!db) return;
7552
+ return new Promise((resolve) => {
7553
+ try {
7554
+ const tx = db.transaction(IDB_STORE, "readwrite");
7555
+ tx.objectStore(IDB_STORE).delete(hashSrc(src));
7556
+ tx.oncomplete = () => resolve();
7557
+ tx.onerror = () => resolve();
7558
+ } catch {
7559
+ resolve();
7384
7560
  }
7385
-
7386
- .accessify-card-label {
7387
- font-size: 16px;
7388
- font-weight: var(--font-bold);
7389
- line-height: 1.22;
7390
- color: var(--text);
7561
+ });
7562
+ }
7563
+ const DEFAULT_API_BASE = "https://accessify-api.accessify.workers.dev";
7564
+ async function fetchServerAltTexts(siteKey, proxyUrl, lang) {
7565
+ const map = /* @__PURE__ */ new Map();
7566
+ try {
7567
+ const base = proxyUrl || DEFAULT_API_BASE;
7568
+ const pageUrl = window.location.origin + window.location.pathname;
7569
+ const res = await fetch(`${base}/v1/manifest?siteKey=${encodeURIComponent(siteKey)}&url=${encodeURIComponent(pageUrl)}&feature=alt_text&variant=${encodeURIComponent(lang)}`, {
7570
+ headers: { "Accept": "application/json" }
7571
+ });
7572
+ if (!res.ok) return map;
7573
+ const data = await res.json();
7574
+ if (data.blocks) {
7575
+ for (const block2 of data.blocks) {
7576
+ if (block2.selector && block2.result) {
7577
+ map.set(block2.selector, block2.result);
7578
+ }
7579
+ }
7391
7580
  }
7392
-
7393
- .accessify-card-desc {
7394
- color: var(--text-secondary);
7395
- font-size: var(--text-sm);
7396
- line-height: 1.5;
7581
+ } catch {
7582
+ }
7583
+ return map;
7584
+ }
7585
+ function persistAltTextToServer(siteKey, proxyUrl, imageUrl, altText2, lang) {
7586
+ try {
7587
+ const base = proxyUrl || DEFAULT_API_BASE;
7588
+ const pageUrl = window.location.origin + window.location.pathname;
7589
+ fetch(`${base}/v1/cache/persist-alt-text`, {
7590
+ method: "POST",
7591
+ headers: { "Content-Type": "application/json" },
7592
+ body: JSON.stringify({ siteKey, pageUrl, imageUrl, altText: altText2, lang })
7593
+ }).catch(() => {
7594
+ });
7595
+ } catch {
7596
+ }
7597
+ }
7598
+ let autoApplied = false;
7599
+ async function autoApplyCachedAltTexts(widgetConfig) {
7600
+ if (autoApplied) return 0;
7601
+ autoApplied = true;
7602
+ const cache = /* @__PURE__ */ new Map();
7603
+ const siteKey = widgetConfig?.siteKey;
7604
+ const proxyUrl = widgetConfig?.proxyUrl || "";
7605
+ const pageLang = widgetConfig?.lang?.split("-")[0] || document.documentElement.lang?.split("-")[0] || "en";
7606
+ if (siteKey) {
7607
+ const serverCache = await fetchServerAltTexts(siteKey, proxyUrl, pageLang);
7608
+ for (const [url, alt] of serverCache) {
7609
+ cache.set(url, alt);
7610
+ setCachedAltText(url, alt, pageLang).catch(() => {
7611
+ });
7397
7612
  }
7398
-
7399
- .accessify-footer {
7400
- display: flex;
7401
- align-items: center;
7402
- justify-content: center;
7403
- gap: var(--space-2);
7404
- padding: 16px var(--space-6) 20px;
7405
- border-top: 1px solid var(--border);
7406
- color: var(--text-secondary);
7407
- font-size: var(--text-xs);
7408
- text-align: center;
7409
- background: color-mix(in srgb, var(--surface-strong) 95%, transparent);
7613
+ }
7614
+ const localCache = await getAllCachedAltTexts();
7615
+ const localOnly = [];
7616
+ for (const [url, alt] of localCache) {
7617
+ if (!cache.has(url)) {
7618
+ cache.set(url, alt);
7619
+ localOnly.push({ imageUrl: url, altText: alt });
7410
7620
  }
7411
-
7412
- .accessify-footer a {
7413
- color: var(--accent-strong);
7414
- text-decoration: none;
7415
- font-weight: var(--font-medium);
7621
+ }
7622
+ if (siteKey && localOnly.length > 0) {
7623
+ try {
7624
+ const base = proxyUrl || DEFAULT_API_BASE;
7625
+ const pageUrl = window.location.origin + window.location.pathname;
7626
+ fetch(`${base}/v1/cache/batch-persist-alt-text`, {
7627
+ method: "POST",
7628
+ headers: { "Content-Type": "application/json" },
7629
+ body: JSON.stringify({
7630
+ siteKey,
7631
+ pageUrl,
7632
+ entries: localOnly.map((e) => ({ ...e, lang: pageLang }))
7633
+ })
7634
+ }).catch(() => {
7635
+ });
7636
+ } catch {
7416
7637
  }
7417
-
7418
- .accessify-footer a:hover {
7419
- text-decoration: underline;
7638
+ }
7639
+ if (cache.size === 0) return 0;
7640
+ let applied = 0;
7641
+ const images = document.querySelectorAll("img");
7642
+ images.forEach((img) => {
7643
+ if (img.closest("#accessify-root")) return;
7644
+ const alt = img.getAttribute("alt");
7645
+ if (alt !== null && alt.trim() !== "") return;
7646
+ const cached = cache.get(img.src);
7647
+ if (cached) {
7648
+ img.setAttribute("alt", cached);
7649
+ img.setAttribute("title", cached);
7650
+ applied++;
7420
7651
  }
7421
-
7422
- @media (prefers-reduced-motion: reduce) {
7423
- *, *::before, *::after {
7424
- animation-duration: 0.01ms !important;
7425
- transition-duration: 0.01ms !important;
7652
+ });
7653
+ const observer = new MutationObserver((mutations) => {
7654
+ for (const m of mutations) {
7655
+ for (const node of m.addedNodes) {
7656
+ const imgs = node instanceof HTMLImageElement ? [node] : node instanceof HTMLElement ? Array.from(node.querySelectorAll("img")) : [];
7657
+ for (const img of imgs) {
7658
+ if (img.closest("#accessify-root")) continue;
7659
+ const a = img.getAttribute("alt");
7660
+ if (a !== null && a.trim() !== "") continue;
7661
+ const c = cache.get(img.src);
7662
+ if (c) {
7663
+ img.setAttribute("alt", c);
7664
+ img.setAttribute("title", c);
7665
+ }
7666
+ }
7426
7667
  }
7427
7668
  }
7428
-
7429
- @media (max-width: 640px) {
7430
- .accessify-panel {
7431
- width: 100vw;
7432
- border-radius: 0;
7669
+ });
7670
+ observer.observe(document.body, { childList: true, subtree: true });
7671
+ setTimeout(() => observer.disconnect(), 3e4);
7672
+ return applied;
7673
+ }
7674
+ function createAltTextModule(aiService, initialLang = "de", serverConfig) {
7675
+ const siteKey = serverConfig?.siteKey || "";
7676
+ const proxyUrl = serverConfig?.proxyUrl || "";
7677
+ let enabled = false;
7678
+ let styleEl = null;
7679
+ let badgeEl = null;
7680
+ let missingAltImages = [];
7681
+ const processedImages = /* @__PURE__ */ new Map();
7682
+ let autoGenerating = false;
7683
+ let tooltipEl = null;
7684
+ const infoButtons = /* @__PURE__ */ new Map();
7685
+ let reportPanelEl = null;
7686
+ function lang() {
7687
+ return getCurrentWidgetLang() || initialLang;
7688
+ }
7689
+ function isDE() {
7690
+ return lang().startsWith("de");
7691
+ }
7692
+ const STYLE_ID = "accessify-alt-text-styles";
7693
+ const HIGHLIGHT_CLASS = "accessify-alt-missing";
7694
+ const BADGE_CLASS = "accessify-alt-badge";
7695
+ function getStyles() {
7696
+ return `
7697
+ .${HIGHLIGHT_CLASS} {
7698
+ outline: 3px dashed #e63946 !important;
7699
+ outline-offset: 3px !important;
7700
+ position: relative !important;
7701
+ transition: outline-color 0.2s ease !important;
7702
+ }
7703
+ .${HIGHLIGHT_CLASS}.accessify-alt-generating::after {
7704
+ content: '\\2026';
7705
+ position: absolute;
7706
+ top: 4px;
7707
+ left: 4px;
7708
+ padding: 2px 6px;
7709
+ background: #f77f00;
7710
+ color: #fff;
7711
+ font-family: system-ui, -apple-system, sans-serif;
7712
+ font-size: 10px;
7713
+ font-weight: 700;
7714
+ border-radius: 3px;
7715
+ line-height: 1.4;
7716
+ pointer-events: none;
7717
+ z-index: 1;
7718
+ }
7719
+ .${HIGHLIGHT_CLASS}.accessify-alt-done {
7720
+ outline-color: #2a9d8f !important;
7721
+ outline-style: solid !important;
7722
+ }
7723
+ .${HIGHLIGHT_CLASS}.accessify-alt-done::after {
7724
+ content: none;
7433
7725
  }
7434
7726
 
7435
- .accessify-header,
7436
- .accessify-status,
7437
- .accessify-footer {
7438
- padding-inline: var(--space-4);
7727
+ .accessify-alt-tooltip {
7728
+ position: fixed;
7729
+ z-index: 2147483647;
7730
+ max-width: 320px;
7731
+ padding: 8px 12px;
7732
+ background: #1a1a2e;
7733
+ color: #e0e0e0;
7734
+ border-radius: 8px;
7735
+ box-shadow: 0 4px 20px rgba(0,0,0,0.4);
7736
+ font-family: system-ui, -apple-system, sans-serif;
7737
+ font-size: 13px;
7738
+ line-height: 1.5;
7739
+ pointer-events: none;
7740
+ word-break: break-word;
7741
+ opacity: 1;
7439
7742
  }
7440
7743
 
7441
- .accessify-header {
7442
- padding-top: var(--space-5);
7744
+ .accessify-alt-info-btn {
7745
+ position: absolute;
7746
+ top: 6px;
7747
+ right: 6px;
7748
+ z-index: 10;
7749
+ width: 22px;
7750
+ height: 22px;
7751
+ padding: 0;
7752
+ border: none;
7753
+ border-radius: 50%;
7754
+ background: rgba(0,0,0,0.6);
7755
+ color: #ccc;
7756
+ font-family: system-ui, -apple-system, sans-serif;
7757
+ font-size: 13px;
7758
+ font-weight: 600;
7759
+ line-height: 22px;
7760
+ text-align: center;
7761
+ cursor: pointer;
7762
+ opacity: 0;
7763
+ transition: opacity 0.15s ease;
7764
+ backdrop-filter: blur(4px);
7765
+ }
7766
+ .${HIGHLIGHT_CLASS}.accessify-alt-done:hover + .accessify-alt-info-btn,
7767
+ .accessify-alt-info-btn:hover {
7768
+ opacity: 1;
7769
+ }
7770
+ .accessify-alt-info-btn:hover {
7771
+ background: rgba(0,0,0,0.8);
7772
+ color: #fff;
7443
7773
  }
7444
7774
 
7445
- .accessify-header p {
7446
- max-width: none;
7775
+ .accessify-alt-report-panel {
7776
+ position: fixed;
7777
+ z-index: 2147483646;
7778
+ width: 240px;
7779
+ padding: 12px;
7780
+ background: #1a1a2e;
7781
+ color: #f0f0f0;
7782
+ border-radius: 10px;
7783
+ box-shadow: 0 8px 32px rgba(0,0,0,0.4);
7784
+ font-family: system-ui, -apple-system, sans-serif;
7785
+ font-size: 12px;
7786
+ line-height: 1.5;
7787
+ }
7788
+ .accessify-alt-report-panel p {
7789
+ margin: 0 0 8px 0;
7790
+ color: #aaa;
7791
+ }
7792
+ .accessify-alt-report-btn {
7793
+ display: inline-flex;
7794
+ align-items: center;
7795
+ gap: 4px;
7796
+ padding: 5px 10px;
7797
+ border: 1px solid rgba(220,53,69,0.3);
7798
+ border-radius: 6px;
7799
+ background: rgba(220,53,69,0.08);
7800
+ color: #f0a0a8;
7801
+ font-size: 11px;
7802
+ cursor: pointer;
7803
+ transition: background 0.15s ease;
7804
+ }
7805
+ .accessify-alt-report-btn:hover { background: rgba(220,53,69,0.2); }
7806
+ .accessify-alt-report-btn.reported {
7807
+ border-color: rgba(42,157,143,0.3);
7808
+ background: rgba(42,157,143,0.1);
7809
+ color: #2a9d8f;
7810
+ cursor: default;
7447
7811
  }
7448
7812
 
7449
- .accessify-header-toolbar {
7450
- grid-template-columns: 1fr;
7813
+ .${BADGE_CLASS} {
7814
+ position: fixed;
7815
+ top: 12px;
7816
+ right: 12px;
7817
+ z-index: 2147483646;
7818
+ display: flex;
7819
+ align-items: center;
7820
+ gap: 6px;
7821
+ padding: 8px 14px;
7822
+ background: #1a1a2e;
7823
+ color: #f0f0f0;
7824
+ border-radius: 8px;
7825
+ box-shadow: 0 4px 16px rgba(0,0,0,0.3);
7826
+ font-family: system-ui, -apple-system, sans-serif;
7827
+ font-size: 13px;
7828
+ user-select: none;
7829
+ }
7830
+ .${BADGE_CLASS}-count {
7831
+ display: inline-flex;
7832
+ align-items: center;
7833
+ justify-content: center;
7834
+ min-width: 22px;
7835
+ height: 22px;
7836
+ padding: 0 6px;
7837
+ background: #e63946;
7838
+ color: #fff;
7839
+ font-size: 12px;
7840
+ font-weight: 700;
7841
+ border-radius: 11px;
7842
+ }
7843
+ `;
7844
+ }
7845
+ function injectStyles() {
7846
+ if (document.getElementById(STYLE_ID)) return;
7847
+ styleEl = document.createElement("style");
7848
+ styleEl.id = STYLE_ID;
7849
+ styleEl.textContent = getStyles();
7850
+ document.head.appendChild(styleEl);
7851
+ }
7852
+ function removeStyles() {
7853
+ styleEl?.remove();
7854
+ styleEl = null;
7855
+ document.getElementById(STYLE_ID)?.remove();
7856
+ }
7857
+ function showTooltip(img) {
7858
+ const text = img.getAttribute("alt") || processedImages.get(img)?.generatedAlt;
7859
+ if (!text) return;
7860
+ hideTooltip();
7861
+ const tip = document.createElement("div");
7862
+ tip.className = "accessify-alt-tooltip";
7863
+ tip.textContent = text;
7864
+ document.body.appendChild(tip);
7865
+ tooltipEl = tip;
7866
+ const rect = img.getBoundingClientRect();
7867
+ const tipRect = tip.getBoundingClientRect();
7868
+ let top = rect.top - tipRect.height - 8;
7869
+ if (top < 4) top = rect.bottom + 8;
7870
+ let left = rect.left + (rect.width - tipRect.width) / 2;
7871
+ left = Math.max(4, Math.min(left, window.innerWidth - tipRect.width - 4));
7872
+ tip.style.top = `${top}px`;
7873
+ tip.style.left = `${left}px`;
7874
+ }
7875
+ function hideTooltip() {
7876
+ tooltipEl?.remove();
7877
+ tooltipEl = null;
7878
+ }
7879
+ function onMouseEnter(e) {
7880
+ showTooltip(e.currentTarget);
7881
+ }
7882
+ function onMouseLeave() {
7883
+ hideTooltip();
7884
+ }
7885
+ function addInfoButton(img) {
7886
+ if (infoButtons.has(img)) return;
7887
+ const parent = img.parentElement;
7888
+ if (parent) {
7889
+ const pos = getComputedStyle(parent).position;
7890
+ if (pos === "static") parent.style.position = "relative";
7891
+ }
7892
+ const btn = document.createElement("button");
7893
+ btn.className = "accessify-alt-info-btn";
7894
+ btn.textContent = "i";
7895
+ btn.setAttribute("aria-label", isDE() ? "Alt-Text melden" : "Report alt text");
7896
+ btn.addEventListener("click", (e) => {
7897
+ e.preventDefault();
7898
+ e.stopPropagation();
7899
+ showReportPanel(img, btn);
7900
+ });
7901
+ img.insertAdjacentElement("afterend", btn);
7902
+ infoButtons.set(img, btn);
7903
+ }
7904
+ function removeInfoButtons() {
7905
+ infoButtons.forEach((btn) => btn.remove());
7906
+ infoButtons.clear();
7907
+ }
7908
+ function showReportPanel(img, anchor) {
7909
+ closeReportPanel();
7910
+ const altText2 = img.getAttribute("alt") || "";
7911
+ const panel = document.createElement("div");
7912
+ panel.className = "accessify-alt-report-panel";
7913
+ const btnRect = anchor.getBoundingClientRect();
7914
+ panel.style.top = `${btnRect.bottom + 6}px`;
7915
+ panel.style.left = `${Math.min(btnRect.left, window.innerWidth - 260)}px`;
7916
+ const desc = document.createElement("p");
7917
+ desc.textContent = isDE() ? "Alt-Text falsch? Melden Sie den Fehler." : "Alt text wrong? Report the error.";
7918
+ panel.appendChild(desc);
7919
+ const reportBtn = document.createElement("button");
7920
+ reportBtn.className = "accessify-alt-report-btn";
7921
+ reportBtn.textContent = isDE() ? "⚠ Fehler melden" : "⚠ Report error";
7922
+ reportBtn.addEventListener("click", async () => {
7923
+ await saveReport(img.src, altText2, lang());
7924
+ await removeCachedAltText(img.src);
7925
+ reportBtn.textContent = isDE() ? "✓ Gemeldet" : "✓ Reported";
7926
+ reportBtn.classList.add("reported");
7927
+ });
7928
+ panel.appendChild(reportBtn);
7929
+ document.body.appendChild(panel);
7930
+ reportPanelEl = panel;
7931
+ setTimeout(() => {
7932
+ const handleOutside = (e) => {
7933
+ if (!panel.contains(e.target) && e.target !== anchor) {
7934
+ closeReportPanel();
7935
+ document.removeEventListener("click", handleOutside);
7936
+ }
7937
+ };
7938
+ document.addEventListener("click", handleOutside);
7939
+ }, 50);
7940
+ const handleEsc = (e) => {
7941
+ if (e.key === "Escape") {
7942
+ closeReportPanel();
7943
+ document.removeEventListener("keydown", handleEsc);
7451
7944
  }
7452
-
7453
- .accessify-body {
7454
- padding: var(--space-3);
7945
+ };
7946
+ document.addEventListener("keydown", handleEsc);
7947
+ }
7948
+ function closeReportPanel() {
7949
+ reportPanelEl?.remove();
7950
+ reportPanelEl = null;
7951
+ }
7952
+ function scanForMissingAlt() {
7953
+ const images = document.querySelectorAll("img");
7954
+ const missing = [];
7955
+ images.forEach((img) => {
7956
+ if (img.closest("#accessify-root")) return;
7957
+ if (img.complete && img.naturalWidth > 0 && (img.naturalWidth < 20 || img.naturalHeight < 20)) return;
7958
+ const alt = img.getAttribute("alt");
7959
+ if (alt === null || alt.trim() === "") missing.push(img);
7960
+ });
7961
+ return missing;
7962
+ }
7963
+ function applyAltText(img, altText2) {
7964
+ img.setAttribute("alt", altText2);
7965
+ img.setAttribute("title", altText2);
7966
+ processedImages.set(img, { generatedAlt: altText2 });
7967
+ if (enabled) {
7968
+ img.classList.add("accessify-alt-done");
7969
+ img.classList.remove("accessify-alt-generating");
7970
+ addInfoButton(img);
7971
+ }
7972
+ img.removeEventListener("mouseenter", onMouseEnter);
7973
+ img.removeEventListener("mouseleave", onMouseLeave);
7974
+ img.addEventListener("mouseenter", onMouseEnter);
7975
+ img.addEventListener("mouseleave", onMouseLeave);
7976
+ }
7977
+ async function generateAll() {
7978
+ if (autoGenerating || !enabled || !aiService) return;
7979
+ autoGenerating = true;
7980
+ const CONCURRENCY = 3;
7981
+ const uncached = [];
7982
+ for (const img of missingAltImages) {
7983
+ if (processedImages.has(img)) continue;
7984
+ const cached = await getCachedAltText(img.src);
7985
+ if (cached) {
7986
+ applyAltText(img, cached);
7987
+ } else {
7988
+ uncached.push(img);
7455
7989
  }
7456
-
7457
- .accessify-control-grid,
7458
- .accessify-features {
7459
- grid-template-columns: 1fr;
7990
+ }
7991
+ updateBadge();
7992
+ if (!uncached.length) {
7993
+ autoGenerating = false;
7994
+ return;
7995
+ }
7996
+ uncached.forEach((img) => img.classList.add("accessify-alt-generating"));
7997
+ for (let i = 0; i < uncached.length; i += CONCURRENCY) {
7998
+ if (!enabled) break;
7999
+ const batch = uncached.slice(i, i + CONCURRENCY);
8000
+ await Promise.all(batch.map(async (img) => {
8001
+ if (!enabled) return;
8002
+ try {
8003
+ const ctx = gatherImageContext(img);
8004
+ const alt = await aiService.generateAltText(img.src, ctx, lang());
8005
+ if (alt && enabled) {
8006
+ applyAltText(img, alt);
8007
+ setCachedAltText(img.src, alt, lang()).catch(() => {
8008
+ });
8009
+ if (siteKey) persistAltTextToServer(siteKey, proxyUrl, img.src, alt, lang());
8010
+ }
8011
+ } catch (err) {
8012
+ console.warn("[Accessify] Alt-text generation failed:", img.src, err);
8013
+ img.classList.remove("accessify-alt-generating");
8014
+ }
8015
+ }));
8016
+ updateBadge();
8017
+ }
8018
+ autoGenerating = false;
8019
+ }
8020
+ async function generateSingle(img) {
8021
+ if (!aiService || !enabled) return;
8022
+ const cached = await getCachedAltText(img.src);
8023
+ if (cached) {
8024
+ applyAltText(img, cached);
8025
+ updateBadge();
8026
+ return;
8027
+ }
8028
+ img.classList.add("accessify-alt-generating");
8029
+ try {
8030
+ const ctx = gatherImageContext(img);
8031
+ const alt = await aiService.generateAltText(img.src, ctx, lang());
8032
+ if (alt && enabled) {
8033
+ applyAltText(img, alt);
8034
+ setCachedAltText(img.src, alt, lang()).catch(() => {
8035
+ });
8036
+ if (siteKey) persistAltTextToServer(siteKey, proxyUrl, img.src, alt, lang());
8037
+ updateBadge();
7460
8038
  }
7461
-
7462
- .accessify-control-card,
7463
- .accessify-card {
7464
- min-height: 0;
8039
+ } catch (err) {
8040
+ console.warn("[Accessify] Alt-text generation failed:", img.src, err);
8041
+ img.classList.remove("accessify-alt-generating");
8042
+ }
8043
+ }
8044
+ function updateBadge() {
8045
+ removeBadge();
8046
+ const remaining = missingAltImages.filter((img) => !processedImages.has(img)).length;
8047
+ const generating = missingAltImages.filter((img) => img.classList.contains("accessify-alt-generating")).length;
8048
+ if (remaining === 0 && missingAltImages.length > 0) {
8049
+ showBadge(isDE() ? `✓ ${missingAltImages.length} Alt-Texte gesetzt` : `✓ ${missingAltImages.length} alt texts applied`, "#2a9d8f", 0);
8050
+ setTimeout(() => removeBadge(), 5e3);
8051
+ return;
8052
+ }
8053
+ if (remaining === 0) return;
8054
+ if (generating > 0) {
8055
+ showBadge(isDE() ? `${generating} Bilder werden analysiert…` : `Analyzing ${generating} images…`, "#f77f00", generating);
8056
+ } else {
8057
+ showBadge(isDE() ? `${remaining} Bilder ohne Alt-Text` : `${remaining} images missing alt text`, "#e63946", remaining);
8058
+ }
8059
+ }
8060
+ function showBadge(text, color, count) {
8061
+ const badge = document.createElement("div");
8062
+ badge.className = BADGE_CLASS;
8063
+ badge.setAttribute("role", "status");
8064
+ badge.setAttribute("aria-live", "polite");
8065
+ if (count > 0) {
8066
+ const c = document.createElement("span");
8067
+ c.className = `${BADGE_CLASS}-count`;
8068
+ c.style.background = color;
8069
+ c.textContent = String(count);
8070
+ badge.appendChild(c);
8071
+ }
8072
+ const label = document.createElement("span");
8073
+ label.textContent = text;
8074
+ badge.appendChild(label);
8075
+ document.body.appendChild(badge);
8076
+ badgeEl = badge;
8077
+ }
8078
+ function removeBadge() {
8079
+ badgeEl?.remove();
8080
+ badgeEl = null;
8081
+ }
8082
+ function gatherImageContext(img) {
8083
+ const parts = [];
8084
+ try {
8085
+ const url = new URL(img.src, window.location.href);
8086
+ const filename = url.pathname.split("/").pop();
8087
+ if (filename) parts.push(`Filename: ${filename}`);
8088
+ } catch {
8089
+ }
8090
+ const figure = img.closest("figure");
8091
+ if (figure) {
8092
+ const caption = figure.querySelector("figcaption");
8093
+ if (caption?.textContent?.trim()) parts.push(`Caption: ${caption.textContent.trim()}`);
8094
+ }
8095
+ const parent = img.parentElement;
8096
+ if (parent) {
8097
+ const heading = parent.querySelector("h1, h2, h3, h4, h5, h6");
8098
+ if (heading?.textContent?.trim()) parts.push(`Nearby heading: ${heading.textContent.trim()}`);
8099
+ }
8100
+ const describedBy = img.getAttribute("aria-describedby");
8101
+ if (describedBy) {
8102
+ const descEl = document.getElementById(describedBy);
8103
+ if (descEl?.textContent?.trim()) parts.push(`Description: ${descEl.textContent.trim()}`);
8104
+ }
8105
+ return parts.join(". ");
8106
+ }
8107
+ let domObserver = null;
8108
+ function tryRegisterImage(img) {
8109
+ if (!enabled) return;
8110
+ if (img.closest("#accessify-root")) return;
8111
+ if (missingAltImages.includes(img)) return;
8112
+ const alt = img.getAttribute("alt");
8113
+ if (alt !== null && alt.trim() !== "") return;
8114
+ function addIfValid() {
8115
+ if (!enabled || missingAltImages.includes(img)) return;
8116
+ if (img.naturalWidth >= 20 && img.naturalHeight >= 20) {
8117
+ img.classList.add(HIGHLIGHT_CLASS);
8118
+ missingAltImages.push(img);
8119
+ updateBadge();
8120
+ generateSingle(img);
8121
+ }
8122
+ }
8123
+ if (img.complete && img.naturalWidth > 0) addIfValid();
8124
+ else img.addEventListener("load", addIfValid, { once: true });
8125
+ }
8126
+ function activate() {
8127
+ if (enabled) return;
8128
+ enabled = true;
8129
+ injectStyles();
8130
+ missingAltImages = scanForMissingAlt();
8131
+ missingAltImages.forEach((img) => img.classList.add(HIGHLIGHT_CLASS));
8132
+ updateBadge();
8133
+ generateAll();
8134
+ document.querySelectorAll("img").forEach((img) => {
8135
+ if (!img.complete) tryRegisterImage(img);
8136
+ });
8137
+ setTimeout(() => {
8138
+ if (enabled) document.querySelectorAll("img").forEach(tryRegisterImage);
8139
+ }, 2e3);
8140
+ domObserver = new MutationObserver((mutations) => {
8141
+ for (const m of mutations) {
8142
+ for (const node of m.addedNodes) {
8143
+ if (node instanceof HTMLImageElement) tryRegisterImage(node);
8144
+ else if (node instanceof HTMLElement) node.querySelectorAll("img").forEach(tryRegisterImage);
8145
+ }
7465
8146
  }
7466
-
7467
- .accessify-trigger {
7468
- ${isBottom ? "bottom: 16px" : "top: 16px"};
7469
- ${isRight ? "right: 16px" : "left: 16px"};
7470
- width: 56px;
7471
- height: 56px;
7472
- border-radius: 18px;
8147
+ });
8148
+ domObserver.observe(document.body, { childList: true, subtree: true });
8149
+ }
8150
+ function deactivate() {
8151
+ enabled = false;
8152
+ autoGenerating = false;
8153
+ domObserver?.disconnect();
8154
+ domObserver = null;
8155
+ hideTooltip();
8156
+ closeReportPanel();
8157
+ removeInfoButtons();
8158
+ removeBadge();
8159
+ missingAltImages.forEach((img) => {
8160
+ img.classList.remove(HIGHLIGHT_CLASS, "accessify-alt-done", "accessify-alt-generating");
8161
+ });
8162
+ missingAltImages = [];
8163
+ removeStyles();
8164
+ }
8165
+ autoApplyCachedAltTexts().catch(() => {
8166
+ });
8167
+ return {
8168
+ id: "alt-text",
8169
+ name: () => isDE() ? "Alt-Text erzeugen" : "Alt-Text Generator",
8170
+ description: isDE() ? "Bildbeschreibungen automatisch erstellen" : "Auto-generate image descriptions",
8171
+ icon: "alt-text",
8172
+ category: "ai",
8173
+ activate,
8174
+ deactivate,
8175
+ getState: () => ({
8176
+ id: "alt-text",
8177
+ enabled,
8178
+ value: {
8179
+ missingCount: missingAltImages.length,
8180
+ processedCount: processedImages.size
7473
8181
  }
7474
- }
7475
- `;
8182
+ })
8183
+ };
7476
8184
  }
8185
+ const altText = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
8186
+ __proto__: null,
8187
+ autoApplyCachedAltTexts,
8188
+ default: createAltTextModule
8189
+ }, Symbol.toStringTag, { value: "Module" }));
7477
8190
  const REMOVED_FEATURES = /* @__PURE__ */ new Set([
7478
8191
  "spacing",
7479
8192
  "dyslexia-font",
@@ -7481,7 +8194,10 @@ const REMOVED_FEATURES = /* @__PURE__ */ new Set([
7481
8194
  "color-blindness",
7482
8195
  "saturation",
7483
8196
  "text-align",
7484
- "line-height"
8197
+ "line-height",
8198
+ "page-structure",
8199
+ "focus-highlight",
8200
+ "auto-scan"
7485
8201
  ]);
7486
8202
  const DEFAULT_CONFIG = {
7487
8203
  position: "bottom-right",
@@ -7494,15 +8210,12 @@ const DEFAULT_CONFIG = {
7494
8210
  "hide-images",
7495
8211
  "reading-guide",
7496
8212
  "reading-mask",
7497
- "focus-highlight",
7498
8213
  "big-cursor",
7499
8214
  "keyboard-nav",
7500
- "page-structure",
7501
8215
  "animation-stop",
7502
8216
  "tts",
7503
8217
  "text-simplify",
7504
- "alt-text",
7505
- "auto-scan"
8218
+ "alt-text"
7506
8219
  ],
7507
8220
  zIndex: 999999,
7508
8221
  compact: false
@@ -7510,10 +8223,52 @@ const DEFAULT_CONFIG = {
7510
8223
  let widgetInstance = null;
7511
8224
  let containerEl = null;
7512
8225
  let config = { ...DEFAULT_CONFIG };
7513
- function init(userConfig = {}) {
8226
+ async function fetchSiteConfig(siteKey, proxyUrl) {
8227
+ try {
8228
+ const base = proxyUrl || "https://accessify-api.accessify.workers.dev";
8229
+ const res = await fetch(`${base}/v1/config/${siteKey}`, {
8230
+ headers: { "Accept": "application/json" }
8231
+ });
8232
+ if (!res.ok) return {};
8233
+ const data = await res.json();
8234
+ const serverCfg = data?.config || {};
8235
+ const mapped = {};
8236
+ if (serverCfg.features?.length) mapped.features = serverCfg.features;
8237
+ if (serverCfg.defaultLang) mapped.lang = serverCfg.defaultLang;
8238
+ if (serverCfg.position) mapped.position = serverCfg.position;
8239
+ if (serverCfg.theme) mapped.theme = serverCfg.theme;
8240
+ if (serverCfg.compact != null) mapped.compact = serverCfg.compact;
8241
+ const brandFields = [
8242
+ "brandPrimaryColor",
8243
+ "brandSurfaceColor",
8244
+ "brandTextColor",
8245
+ "brandBorderColor",
8246
+ "brandCardColor",
8247
+ "brandAccentColor",
8248
+ "brandTextDimColor",
8249
+ "brandTriggerColor",
8250
+ "brandTriggerIconColor",
8251
+ "brandHoverColor"
8252
+ ];
8253
+ for (const field of brandFields) {
8254
+ if (serverCfg[field]) mapped[field] = serverCfg[field];
8255
+ }
8256
+ if (serverCfg.panelWidth) mapped.panelWidth = serverCfg.panelWidth;
8257
+ return mapped;
8258
+ } catch {
8259
+ return {};
8260
+ }
8261
+ }
8262
+ async function init(userConfig = {}) {
7514
8263
  if (widgetInstance) return;
7515
8264
  const dataConfig = window.__accessify_dataConfig || {};
7516
8265
  config = { ...DEFAULT_CONFIG, ...dataConfig, ...userConfig };
8266
+ const siteKey = config.siteKey || config.siteKey;
8267
+ const proxyUrl = config.proxyUrl || config.proxyUrl;
8268
+ if (siteKey) {
8269
+ const serverConfig = await fetchSiteConfig(siteKey, proxyUrl || "");
8270
+ config = { ...DEFAULT_CONFIG, ...serverConfig, ...dataConfig, ...userConfig };
8271
+ }
7517
8272
  config.features = (config.features || DEFAULT_CONFIG.features).filter((feature) => !REMOVED_FEATURES.has(feature));
7518
8273
  containerEl = document.createElement("div");
7519
8274
  containerEl.id = "accessify-root";
@@ -7554,7 +8309,29 @@ function init(userConfig = {}) {
7554
8309
  if (handled) e.stopImmediatePropagation();
7555
8310
  }, true);
7556
8311
  }
8312
+ window.addEventListener("accessify:reposition", ((e) => {
8313
+ const newPos = e.detail?.position;
8314
+ if (newPos && config) {
8315
+ config.position = newPos;
8316
+ sheet.replaceSync(createWidgetStyles(config));
8317
+ }
8318
+ }));
8319
+ window.addEventListener("message", (e) => {
8320
+ if (e.data?.type === "accessify:preview-config") {
8321
+ const preview = e.data.config || {};
8322
+ Object.assign(config, preview);
8323
+ sheet.replaceSync(createWidgetStyles(config));
8324
+ }
8325
+ if (e.data?.type === "accessify:open") {
8326
+ const panel = shadow.querySelector(".accessify-panel");
8327
+ const trigger = shadow.querySelector(".accessify-trigger");
8328
+ if (panel) panel.setAttribute("aria-hidden", "false");
8329
+ if (trigger) trigger.setAttribute("aria-expanded", "true");
8330
+ }
8331
+ });
7557
8332
  document.body.appendChild(containerEl);
8333
+ autoApplyCachedAltTexts(config).catch(() => {
8334
+ });
7558
8335
  config.onReady?.();
7559
8336
  }
7560
8337
  function destroy() {
@@ -7580,16 +8357,20 @@ if (api?.q) {
7580
8357
  api.q.forEach((args) => exec(...args));
7581
8358
  api.q = [];
7582
8359
  }
7583
- window.Accessify = function(cmd, ...args) {
8360
+ const finalApi = function(cmd, ...args) {
7584
8361
  exec(cmd, ...args);
7585
8362
  };
7586
- window.Accessify._loaded = true;
7587
- window.A11yPlus = window.Accessify;
8363
+ finalApi._loaded = true;
8364
+ Object.defineProperty(finalApi, "config", {
8365
+ get: () => config,
8366
+ enumerable: true
8367
+ });
8368
+ window.Accessify = finalApi;
8369
+ window.A11yPlus = finalApi;
7588
8370
  export {
7589
- RateLimitError as R,
7590
8371
  destroy as d,
7591
8372
  getCurrentWidgetLang as g,
7592
8373
  init as i,
7593
8374
  t
7594
8375
  };
7595
- //# sourceMappingURL=index-qmiN2JAz.js.map
8376
+ //# sourceMappingURL=index-CsJDqdBW.js.map