accessify-widget 0.3.39 → 0.3.40

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.
@@ -1,4 +1,4 @@
1
- import { d, i } from "./index-SYghhXzh.js";
1
+ import { d, i } from "./index-BD3C-sG-.js";
2
2
  export {
3
3
  d as destroy,
4
4
  i as init
@@ -0,0 +1,176 @@
1
+ const TOKENS = {
2
+ light: {
3
+ colorScheme: "light",
4
+ pageBg: "#fbf7ef",
5
+ text: "#1a1a1a",
6
+ textStrong: "#0d0d0d",
7
+ link: "#0047b3",
8
+ linkVisited: "#3d2b85",
9
+ focusRing: "#0047b3",
10
+ borderContent: "#888078",
11
+ inputBg: "#ffffff",
12
+ inputBorder: "#6f675d",
13
+ imgFilter: ""
14
+ },
15
+ dark: {
16
+ colorScheme: "dark",
17
+ pageBg: "#101418",
18
+ text: "#e8e4dc",
19
+ textStrong: "#ffffff",
20
+ link: "#7cc8f5",
21
+ linkVisited: "#b8a0e8",
22
+ focusRing: "#7cc8f5",
23
+ borderContent: "#3a4a58",
24
+ inputBg: "#1a2028",
25
+ inputBorder: "#4a5a68",
26
+ imgFilter: "brightness(0.90) contrast(1.06)"
27
+ },
28
+ high: {
29
+ colorScheme: "dark",
30
+ pageBg: "#000000",
31
+ text: "#ffffff",
32
+ textStrong: "#ffffff",
33
+ link: "#ffff00",
34
+ linkVisited: "#ffff00",
35
+ focusRing: "#ffff00",
36
+ borderContent: "#ffffff",
37
+ inputBg: "#000000",
38
+ inputBorder: "#ffffff",
39
+ imgFilter: "contrast(1.25) brightness(0.95)"
40
+ }
41
+ };
42
+ const EX = ":not(#accessify-root):not(#accessify-root *)";
43
+ function buildCSS(mode) {
44
+ const t = TOKENS[mode];
45
+ const isHigh = mode === "high";
46
+ const base = `
47
+ html {
48
+ color-scheme: ${t.colorScheme} !important;
49
+ }
50
+ html, body {
51
+ background-color: ${t.pageBg} !important;
52
+ }
53
+ `;
54
+ const textColor = `
55
+ body *${EX} {
56
+ color: ${t.text} !important;
57
+ }
58
+ body :where(h1, h2, h3, h4, h5, h6, strong, b, th)${EX} {
59
+ color: ${t.textStrong} !important;
60
+ }
61
+ `;
62
+ const links = `
63
+ body :where(a)${EX} {
64
+ color: ${t.link} !important;
65
+ text-decoration: underline !important;
66
+ text-decoration-color: ${t.link} !important;
67
+ ${isHigh ? "text-decoration-thickness: 2px !important; text-underline-offset: 3px !important;" : ""}
68
+ }
69
+ body :where(a:visited)${EX} {
70
+ color: ${t.linkVisited} !important;
71
+ }
72
+ body :where(a:hover, a:focus)${EX} {
73
+ opacity: 0.85 !important;
74
+ }
75
+ `;
76
+ const forms = `
77
+ body :where(input, textarea, select)${EX} {
78
+ background-color: ${t.inputBg} !important;
79
+ color: ${t.text} !important;
80
+ border: 1px solid ${t.inputBorder} !important;
81
+ box-shadow: none !important;
82
+ }
83
+ body :where(button, [role="button"])${EX} {
84
+ color: ${t.text} !important;
85
+ border-color: ${t.inputBorder} !important;
86
+ ${isHigh ? `background-color: ${t.pageBg} !important; border: 2px solid ${t.inputBorder} !important;` : ""}
87
+ }
88
+ `;
89
+ const focus = `
90
+ body :where(a, button, input, textarea, select, [tabindex])${EX}:focus-visible {
91
+ outline: ${isHigh ? "3px" : "2px"} solid ${t.focusRing} !important;
92
+ outline-offset: 2px !important;
93
+ }
94
+ `;
95
+ const borders = `
96
+ body :where(table, th, td, hr, fieldset)${EX} {
97
+ border-color: ${t.borderContent} !important;
98
+ }
99
+ `;
100
+ const images = t.imgFilter ? `
101
+ body :where(img, video, picture)${EX} {
102
+ filter: ${t.imgFilter} !important;
103
+ }
104
+ ` : "";
105
+ const highExtras = isHigh ? `
106
+ body :where(::placeholder)${EX} {
107
+ color: #aaaaaa !important;
108
+ opacity: 1 !important;
109
+ }
110
+ body :where(::selection) {
111
+ background: #ffff00 !important;
112
+ color: #000000 !important;
113
+ }
114
+ body :where(mark)${EX} {
115
+ background: #ffff00 !important;
116
+ color: #000000 !important;
117
+ }
118
+ ` : "";
119
+ const sectionBg = `
120
+ body :where(main, article, aside, header, footer, section, nav)${EX} {
121
+ background-color: ${t.pageBg} !important;
122
+ }
123
+ `;
124
+ return base + textColor + links + forms + focus + borders + images + highExtras + sectionBg;
125
+ }
126
+ function createContrastModule() {
127
+ let currentMode = "off";
128
+ const STYLE_ID = "accessify-contrast";
129
+ const STORAGE_KEY = "accessify-contrast-mode";
130
+ function applyStyles(mode) {
131
+ let styleEl = document.getElementById(STYLE_ID);
132
+ if (mode === "off") {
133
+ styleEl?.remove();
134
+ return;
135
+ }
136
+ if (!styleEl) {
137
+ styleEl = document.createElement("style");
138
+ styleEl.id = STYLE_ID;
139
+ document.head.appendChild(styleEl);
140
+ }
141
+ styleEl.textContent = buildCSS(mode);
142
+ }
143
+ function activate() {
144
+ const saved = localStorage.getItem(STORAGE_KEY);
145
+ currentMode = saved === "light" || saved === "dark" || saved === "high" ? saved : "dark";
146
+ applyStyles(currentMode);
147
+ }
148
+ function deactivate() {
149
+ currentMode = "off";
150
+ applyStyles("off");
151
+ localStorage.removeItem(STORAGE_KEY);
152
+ }
153
+ return {
154
+ id: "contrast",
155
+ name: () => "Contrast",
156
+ description: "Increase contrast for better readability",
157
+ icon: "contrast",
158
+ category: "visual",
159
+ activate,
160
+ deactivate,
161
+ getState: () => ({ id: "contrast", enabled: currentMode !== "off", value: currentMode }),
162
+ setState: (mode) => {
163
+ currentMode = mode === "light" || mode === "dark" || mode === "high" ? mode : "off";
164
+ applyStyles(currentMode);
165
+ if (currentMode === "off") {
166
+ localStorage.removeItem(STORAGE_KEY);
167
+ } else {
168
+ localStorage.setItem(STORAGE_KEY, currentMode);
169
+ }
170
+ }
171
+ };
172
+ }
173
+ export {
174
+ createContrastModule as default
175
+ };
176
+ //# sourceMappingURL=contrast-F7lHj833.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contrast-F7lHj833.js","sources":["../src/features/contrast.ts"],"sourcesContent":["// ---------------------------------------------------------------------------\n// Accessify – Contrast Modes (Accessibility Feature)\n// ---------------------------------------------------------------------------\n//\n// Three modes: light, dark, high — each as a clearly defined token set.\n//\n// Design principles:\n// 1. CONTENT elements (text, headings, links, buttons, form controls) get\n// explicit color overrides — these are what users need to read.\n// 2. STRUCTURAL elements (wrapper divs, sections, nav) get background only\n// via `html` and `body` — not individually. This prevents breaking\n// Framer/CSS-Grid/Flex layouts where divs use fit-content, overflow:hidden,\n// or fixed heights.\n// 3. The widget itself (inside #accessify-root / Shadow DOM) is NEVER touched.\n// 4. Focus indicators are defined in ALL modes, not just high contrast.\n// 5. border-color is NOT globally overridden — only on elements that have\n// visible borders for content separation (tables, fieldsets, hr).\n//\n// Selector strategy:\n// - `:where()` for zero-specificity (site styles can still win if needed,\n// but `!important` ensures accessibility overrides take priority).\n// - `body :where(...)` scopes to page content.\n// - `body *:not(#accessify-root):not(#accessify-root *)` used only where\n// we need broad text color coverage.\n// - Framer-safe: no background-color on generic div/section/article — only\n// on html/body. Content readability comes from text color, not from\n// painting every container.\n//\n// ---------------------------------------------------------------------------\n\nimport type { FeatureModule, FeatureState } from '../types';\n\ntype ContrastMode = 'off' | 'light' | 'dark' | 'high';\n\n// ---------------------------------------------------------------------------\n// Token definitions — each mode is a self-contained color system\n// ---------------------------------------------------------------------------\n\ninterface ContrastTokens {\n colorScheme: string;\n pageBg: string;\n text: string;\n textStrong: string; // headings, bold\n link: string;\n linkVisited: string;\n focusRing: string;\n borderContent: string; // for tables, hr, fieldset — NOT every div\n inputBg: string;\n inputBorder: string;\n imgFilter: string; // empty string = no filter\n}\n\nconst TOKENS: Record<Exclude<ContrastMode, 'off'>, ContrastTokens> = {\n light: {\n colorScheme: 'light',\n pageBg: '#fbf7ef',\n text: '#1a1a1a',\n textStrong: '#0d0d0d',\n link: '#0047b3',\n linkVisited: '#3d2b85',\n focusRing: '#0047b3',\n borderContent:'#888078',\n inputBg: '#ffffff',\n inputBorder: '#6f675d',\n imgFilter: '',\n },\n dark: {\n colorScheme: 'dark',\n pageBg: '#101418',\n text: '#e8e4dc',\n textStrong: '#ffffff',\n link: '#7cc8f5',\n linkVisited: '#b8a0e8',\n focusRing: '#7cc8f5',\n borderContent:'#3a4a58',\n inputBg: '#1a2028',\n inputBorder: '#4a5a68',\n imgFilter: 'brightness(0.90) contrast(1.06)',\n },\n high: {\n colorScheme: 'dark',\n pageBg: '#000000',\n text: '#ffffff',\n textStrong: '#ffffff',\n link: '#ffff00',\n linkVisited: '#ffff00',\n focusRing: '#ffff00',\n borderContent:'#ffffff',\n inputBg: '#000000',\n inputBorder: '#ffffff',\n imgFilter: 'contrast(1.25) brightness(0.95)',\n },\n};\n\n// ---------------------------------------------------------------------------\n// CSS generation — separated into logical layers\n// ---------------------------------------------------------------------------\n\n/** Elements to exclude from page-level contrast (the widget itself) */\nconst EX = ':not(#accessify-root):not(#accessify-root *)';\n\nfunction buildCSS(mode: Exclude<ContrastMode, 'off'>): string {\n const t = TOKENS[mode];\n const isHigh = mode === 'high';\n\n // ── Layer 1: Page-level base (html/body only) ──\n // Only html+body get background. NOT every div — that breaks Framer layouts\n // where wrapper divs use overflow:hidden, fixed heights, fit-content etc.\n const base = `\n html {\n color-scheme: ${t.colorScheme} !important;\n }\n html, body {\n background-color: ${t.pageBg} !important;\n }\n `;\n\n // ── Layer 2: Text color on ALL content elements ──\n // Using body * ensures text inside any container is readable, without\n // painting the container's background (which would break layouts).\n const textColor = `\n body *${EX} {\n color: ${t.text} !important;\n }\n body :where(h1, h2, h3, h4, h5, h6, strong, b, th)${EX} {\n color: ${t.textStrong} !important;\n }\n `;\n\n // ── Layer 3: Links — distinct color + underline for visibility ──\n const links = `\n body :where(a)${EX} {\n color: ${t.link} !important;\n text-decoration: underline !important;\n text-decoration-color: ${t.link} !important;\n ${isHigh ? 'text-decoration-thickness: 2px !important; text-underline-offset: 3px !important;' : ''}\n }\n body :where(a:visited)${EX} {\n color: ${t.linkVisited} !important;\n }\n body :where(a:hover, a:focus)${EX} {\n opacity: 0.85 !important;\n }\n `;\n\n // ── Layer 4: Form controls — explicit bg + border for readability ──\n // These get background because they ARE content, not structural wrappers.\n const forms = `\n body :where(input, textarea, select)${EX} {\n background-color: ${t.inputBg} !important;\n color: ${t.text} !important;\n border: 1px solid ${t.inputBorder} !important;\n box-shadow: none !important;\n }\n body :where(button, [role=\"button\"])${EX} {\n color: ${t.text} !important;\n border-color: ${t.inputBorder} !important;\n ${isHigh ? `background-color: ${t.pageBg} !important; border: 2px solid ${t.inputBorder} !important;` : ''}\n }\n `;\n\n // ── Layer 5: Focus indicators — in ALL modes, stronger in high ──\n const focus = `\n body :where(a, button, input, textarea, select, [tabindex])${EX}:focus-visible {\n outline: ${isHigh ? '3px' : '2px'} solid ${t.focusRing} !important;\n outline-offset: 2px !important;\n }\n `;\n\n // ── Layer 6: Content borders — only on elements that visually separate ──\n // NOT on generic divs — that destroys Framer card layouts.\n const borders = `\n body :where(table, th, td, hr, fieldset)${EX} {\n border-color: ${t.borderContent} !important;\n }\n `;\n\n // ── Layer 7: Images — gentle filter, skip decorative SVG icons ──\n const images = t.imgFilter ? `\n body :where(img, video, picture)${EX} {\n filter: ${t.imgFilter} !important;\n }\n ` : '';\n\n // ── Layer 8: High contrast extras ──\n const highExtras = isHigh ? `\n body :where(::placeholder)${EX} {\n color: #aaaaaa !important;\n opacity: 1 !important;\n }\n body :where(::selection) {\n background: #ffff00 !important;\n color: #000000 !important;\n }\n body :where(mark)${EX} {\n background: #ffff00 !important;\n color: #000000 !important;\n }\n ` : '';\n\n // ── Layer 9: Background for large content sections (NOT small wrappers) ──\n // Only target semantic HTML5 landmarks + explicitly large containers.\n // Framer wraps everything in nested divs — we do NOT paint those.\n // Instead, the html/body bg shines through. For sections that have their\n // own bg (hero, colored blocks), we override only semantic elements.\n const sectionBg = `\n body :where(main, article, aside, header, footer, section, nav)${EX} {\n background-color: ${t.pageBg} !important;\n }\n `;\n\n return base + textColor + links + forms + focus + borders + images + highExtras + sectionBg;\n}\n\n// ---------------------------------------------------------------------------\n// Module\n// ---------------------------------------------------------------------------\n\nexport default function createContrastModule(): FeatureModule {\n let currentMode: ContrastMode = 'off';\n const STYLE_ID = 'accessify-contrast';\n const STORAGE_KEY = 'accessify-contrast-mode';\n\n function applyStyles(mode: ContrastMode) {\n let styleEl = document.getElementById(STYLE_ID);\n if (mode === 'off') {\n styleEl?.remove();\n return;\n }\n if (!styleEl) {\n styleEl = document.createElement('style');\n styleEl.id = STYLE_ID;\n document.head.appendChild(styleEl);\n }\n styleEl.textContent = buildCSS(mode);\n }\n\n function activate() {\n const saved = localStorage.getItem(STORAGE_KEY) as ContrastMode;\n currentMode = saved === 'light' || saved === 'dark' || saved === 'high' ? saved : 'dark';\n applyStyles(currentMode);\n }\n\n function deactivate() {\n currentMode = 'off';\n applyStyles('off');\n localStorage.removeItem(STORAGE_KEY);\n }\n\n return {\n id: 'contrast',\n name: () => 'Contrast',\n description: 'Increase contrast for better readability',\n icon: 'contrast',\n category: 'visual',\n activate,\n deactivate,\n getState: (): FeatureState => ({ id: 'contrast', enabled: currentMode !== 'off', value: currentMode }),\n setState: (mode: ContrastMode) => {\n currentMode = mode === 'light' || mode === 'dark' || mode === 'high' ? mode : 'off';\n applyStyles(currentMode);\n if (currentMode === 'off') {\n localStorage.removeItem(STORAGE_KEY);\n } else {\n localStorage.setItem(STORAGE_KEY, currentMode);\n }\n },\n };\n}\n"],"names":[],"mappings":"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"}
@@ -6516,12 +6516,16 @@ function getEnglishSimplificationPrompt() {
6516
6516
 
6517
6517
  Return ONLY the simplified text.`;
6518
6518
  }
6519
- 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>`);
6519
+ var root_3$1 = /* @__PURE__ */ from_html(`<span class="accessify-chip-check" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg></span>`);
6520
+ var root_4 = /* @__PURE__ */ from_html(`<span class="accessify-chip-icon" aria-hidden="true"></span>`);
6521
+ var root_2$1 = /* @__PURE__ */ from_html(`<button class="accessify-chip accessify-chip--icon"><!> <span> </span></button>`);
6520
6522
  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>`);
6521
- var root_4 = /* @__PURE__ */ from_html(`<button class="accessify-chip accessify-chip--icon"><span aria-hidden="true">A</span> <span> </span></button>`);
6522
- 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-chip-row"></div></div>`);
6523
- var root_6 = /* @__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" role="note"><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></div>`);
6524
- var root_5 = /* @__PURE__ */ from_html(`<div class="accessify-features"></div>`);
6523
+ var root_7 = /* @__PURE__ */ from_html(`<span class="accessify-chip-check" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"></path></svg></span>`);
6524
+ var root_8 = /* @__PURE__ */ from_html(`<span aria-hidden="true">A</span>`);
6525
+ var root_6 = /* @__PURE__ */ from_html(`<button class="accessify-chip accessify-chip--icon"><!> <span> </span></button>`);
6526
+ var root_5 = /* @__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>`);
6527
+ var root_10 = /* @__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" role="note"><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></div>`);
6528
+ var root_9 = /* @__PURE__ */ from_html(`<div class="accessify-features"></div>`);
6525
6529
  var root$2 = /* @__PURE__ */ from_html(`<!> <!> <div class="accessify-section-divider"></div> <!>`, 1);
6526
6530
  function FeatureGrid($$anchor, $$props) {
6527
6531
  push($$props, true);
@@ -6622,16 +6626,16 @@ function FeatureGrid($$anchor, $$props) {
6622
6626
  const AI_FEATURES = /* @__PURE__ */ new Set(["text-simplify", "alt-text"]);
6623
6627
  const loadedModules = /* @__PURE__ */ new Map();
6624
6628
  const FEATURE_LOADERS = {
6625
- contrast: () => import("./contrast-CqsICAkU.js"),
6629
+ contrast: () => import("./contrast-F7lHj833.js"),
6626
6630
  "text-size": () => import("./text-size-m_mHNPWo.js"),
6627
- "keyboard-nav": () => import("./keyboard-nav-BPNT4h61.js"),
6631
+ "keyboard-nav": () => import("./keyboard-nav-ohhgkfVh.js"),
6628
6632
  "link-highlight": () => import("./link-highlight-DBGm067Y.js"),
6629
6633
  "reading-guide": () => import("./reading-guide-VT8NciIL.js"),
6630
6634
  "reading-mask": () => import("./reading-mask-BABChuCz.js"),
6631
6635
  "animation-stop": () => import("./animation-stop-_chC8bg1.js"),
6632
6636
  "hide-images": () => import("./hide-images-B_LeCBcd.js"),
6633
6637
  "big-cursor": () => import("./big-cursor-B2UKu9dQ.js"),
6634
- "page-structure": () => import("./page-structure-Cg1a9HyG.js"),
6638
+ "page-structure": () => import("./page-structure-BuecyE3V.js"),
6635
6639
  tts: () => import("./tts-CjszLRnb.js"),
6636
6640
  "text-simplify": () => import("./text-simplify-CK2GFhq2.js"),
6637
6641
  "alt-text": () => Promise.resolve().then(() => altText)
@@ -6780,7 +6784,7 @@ function FeatureGrid($$anchor, $$props) {
6780
6784
  var fragment = root$2();
6781
6785
  var node = first_child(fragment);
6782
6786
  {
6783
- var consequent = ($$anchor2) => {
6787
+ var consequent_1 = ($$anchor2) => {
6784
6788
  var div = root_1$2();
6785
6789
  var div_1 = child(div);
6786
6790
  var span = child(div_1);
@@ -6790,10 +6794,24 @@ function FeatureGrid($$anchor, $$props) {
6790
6794
  var div_2 = sibling(div_1, 2);
6791
6795
  each(div_2, 21, () => CONTRAST_MODES, index, ($$anchor3, mode) => {
6792
6796
  var button = root_2$1();
6793
- var span_2 = child(button);
6794
- html(span_2, () => get(mode).icon, true);
6795
- var span_3 = sibling(span_2, 2);
6796
- var text_1 = child(span_3);
6797
+ var node_1 = child(button);
6798
+ {
6799
+ var consequent = ($$anchor4) => {
6800
+ var span_2 = root_3$1();
6801
+ append($$anchor4, span_2);
6802
+ };
6803
+ var alternate = ($$anchor4) => {
6804
+ var span_3 = root_4();
6805
+ html(span_3, () => get(mode).icon, true);
6806
+ append($$anchor4, span_3);
6807
+ };
6808
+ if_block(node_1, ($$render) => {
6809
+ if (get(contrastMode) === get(mode).id) $$render(consequent);
6810
+ else $$render(alternate, -1);
6811
+ });
6812
+ }
6813
+ var span_4 = sibling(node_1, 2);
6814
+ var text_1 = child(span_4);
6797
6815
  template_effect(
6798
6816
  ($0) => {
6799
6817
  set_attribute(button, "data-active", get(contrastMode) === get(mode).id);
@@ -6819,18 +6837,18 @@ function FeatureGrid($$anchor, $$props) {
6819
6837
  };
6820
6838
  var d = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("contrast"));
6821
6839
  if_block(node, ($$render) => {
6822
- if (get(d)) $$render(consequent);
6840
+ if (get(d)) $$render(consequent_1);
6823
6841
  });
6824
6842
  }
6825
- var node_1 = sibling(node, 2);
6843
+ var node_2 = sibling(node, 2);
6826
6844
  {
6827
- var consequent_1 = ($$anchor2) => {
6828
- var div_3 = root_3$1();
6845
+ var consequent_3 = ($$anchor2) => {
6846
+ var div_3 = root_5();
6829
6847
  var div_4 = child(div_3);
6830
- var span_4 = child(div_4);
6831
- html(span_4, () => getIcon("text-size"), true);
6832
- var span_5 = sibling(span_4, 2);
6833
- var text_2 = child(span_5);
6848
+ var span_5 = child(div_4);
6849
+ html(span_5, () => getIcon("text-size"), true);
6850
+ var span_6 = sibling(span_5, 2);
6851
+ var text_2 = child(span_6);
6834
6852
  var div_5 = sibling(div_4, 2);
6835
6853
  each(
6836
6854
  div_5,
@@ -6854,14 +6872,28 @@ function FeatureGrid($$anchor, $$props) {
6854
6872
  ],
6855
6873
  index,
6856
6874
  ($$anchor3, step) => {
6857
- var button_1 = root_4();
6858
- var span_6 = child(button_1);
6859
- var span_7 = sibling(span_6, 2);
6860
- var text_3 = child(span_7);
6875
+ var button_1 = root_6();
6876
+ var node_3 = child(button_1);
6877
+ {
6878
+ var consequent_2 = ($$anchor4) => {
6879
+ var span_7 = root_7();
6880
+ append($$anchor4, span_7);
6881
+ };
6882
+ var alternate_1 = ($$anchor4) => {
6883
+ var span_8 = root_8();
6884
+ template_effect(() => set_style(span_8, `font-size:${get(step).size ?? ""};font-weight:700;line-height:1`));
6885
+ append($$anchor4, span_8);
6886
+ };
6887
+ if_block(node_3, ($$render) => {
6888
+ if (get(textSize) === get(step).pct) $$render(consequent_2);
6889
+ else $$render(alternate_1, -1);
6890
+ });
6891
+ }
6892
+ var span_9 = sibling(node_3, 2);
6893
+ var text_3 = child(span_9);
6861
6894
  template_effect(() => {
6862
6895
  set_attribute(button_1, "data-active", get(textSize) === get(step).pct);
6863
6896
  set_attribute(button_1, "aria-pressed", get(textSize) === get(step).pct);
6864
- set_style(span_6, `font-size:${get(step).size ?? ""};font-weight:700;line-height:1`);
6865
6897
  set_text(text_3, get(step).label);
6866
6898
  });
6867
6899
  delegated("click", button_1, () => setTextSize(get(textSize) === get(step).pct ? 100 : get(step).pct));
@@ -6881,14 +6913,14 @@ function FeatureGrid($$anchor, $$props) {
6881
6913
  append($$anchor2, div_3);
6882
6914
  };
6883
6915
  var d_1 = /* @__PURE__ */ user_derived(() => get(visibleFeatureIds).has("text-size"));
6884
- if_block(node_1, ($$render) => {
6885
- if (get(d_1)) $$render(consequent_1);
6916
+ if_block(node_2, ($$render) => {
6917
+ if (get(d_1)) $$render(consequent_3);
6886
6918
  });
6887
6919
  }
6888
- var node_2 = sibling(node_1, 4);
6920
+ var node_4 = sibling(node_2, 4);
6889
6921
  {
6890
- var consequent_2 = ($$anchor2) => {
6891
- var div_6 = root_5();
6922
+ var consequent_4 = ($$anchor2) => {
6923
+ var div_6 = root_9();
6892
6924
  each(
6893
6925
  div_6,
6894
6926
  21,
@@ -6900,21 +6932,21 @@ function FeatureGrid($$anchor, $$props) {
6900
6932
  (feature) => feature.id,
6901
6933
  ($$anchor3, feature) => {
6902
6934
  const isActive = /* @__PURE__ */ user_derived(() => $$props.activeFeatures.get(get(feature).id) ?? false);
6903
- var div_7 = root_6();
6935
+ var div_7 = root_10();
6904
6936
  var button_2 = child(div_7);
6905
- var span_8 = child(button_2);
6906
- html(span_8, () => getIcon(get(feature).iconId), true);
6907
- var span_9 = sibling(span_8, 2);
6908
- var text_4 = child(span_9);
6909
- var span_10 = sibling(button_2, 2);
6937
+ var span_10 = child(button_2);
6938
+ html(span_10, () => getIcon(get(feature).iconId), true);
6939
+ var span_11 = sibling(span_10, 2);
6940
+ var text_4 = child(span_11);
6941
+ var span_12 = sibling(button_2, 2);
6910
6942
  template_effect(
6911
6943
  ($0, $1, $2, $3) => {
6912
6944
  set_attribute(button_2, "data-active", get(isActive));
6913
6945
  set_attribute(button_2, "aria-checked", get(isActive));
6914
6946
  set_attribute(button_2, "aria-label", $0);
6915
6947
  set_text(text_4, $1);
6916
- set_attribute(span_10, "aria-label", $2);
6917
- set_attribute(span_10, "title", $3);
6948
+ set_attribute(span_12, "aria-label", $2);
6949
+ set_attribute(span_12, "title", $3);
6918
6950
  },
6919
6951
  [
6920
6952
  () => t(get(feature).nameKey, $$props.config.lang),
@@ -6929,8 +6961,8 @@ function FeatureGrid($$anchor, $$props) {
6929
6961
  );
6930
6962
  append($$anchor2, div_6);
6931
6963
  };
6932
- if_block(node_2, ($$render) => {
6933
- if (get(visualFeatures).length > 0 || get(readingFeatures).length > 0 || get(aiFeatures).length > 0) $$render(consequent_2);
6964
+ if_block(node_4, ($$render) => {
6965
+ if (get(visualFeatures).length > 0 || get(readingFeatures).length > 0 || get(aiFeatures).length > 0) $$render(consequent_4);
6934
6966
  });
6935
6967
  }
6936
6968
  append($$anchor, fragment);
@@ -7962,10 +7994,21 @@ function createWidgetStyles(config2) {
7962
7994
  transition: background var(--fast), color var(--fast), border-color var(--fast);
7963
7995
  }
7964
7996
  .accessify-chip:hover { border-color: var(--border-hl); background: var(--surface-hover); }
7965
- .accessify-chip[data-active="true"] { background: var(--accent); color: var(--accent-on); border-color: var(--accent); }
7966
- .accessify-chip--icon { gap: 6px; }
7967
- .accessify-chip-icon { display: inline-flex; width: 14px; height: 14px; flex-shrink: 0; }
7968
- .accessify-chip-icon svg { width: 14px; height: 14px; }
7997
+ .accessify-chip[data-active="true"] {
7998
+ background: var(--accent); color: var(--accent-on);
7999
+ border-color: var(--accent);
8000
+ border-width: 2px;
8001
+ font-weight: 700;
8002
+ }
8003
+ .accessify-chip--icon { gap: 6px; flex-direction: column; }
8004
+ .accessify-chip-icon { display: inline-flex; width: 16px; height: 16px; flex-shrink: 0; }
8005
+ .accessify-chip-icon svg { width: 16px; height: 16px; }
8006
+ .accessify-chip-check {
8007
+ display: inline-flex; align-items: center; justify-content: center;
8008
+ width: 20px; height: 20px; border-radius: 50%;
8009
+ background: rgba(255,255,255,0.25); flex-shrink: 0;
8010
+ }
8011
+ .accessify-chip-check svg { width: 14px; height: 14px; }
7969
8012
 
7970
8013
  /* Text Size stepper */
7971
8014
  .accessify-control-row:has(.accessify-stepper) {
@@ -8945,4 +8988,4 @@ export {
8945
8988
  init as i,
8946
8989
  t
8947
8990
  };
8948
- //# sourceMappingURL=index-SYghhXzh.js.map
8991
+ //# sourceMappingURL=index-BD3C-sG-.js.map