nodality 1.3.15 → 1.3.16

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.
Files changed (218) hide show
  1. package/bin/install-skill.mjs +3 -3
  2. package/bin/mcp-server.mjs +46 -1
  3. package/bin/nodality.mjs +103 -0
  4. package/dist/animator.cjs.js.LICENSE.txt +1 -1
  5. package/dist/animator.esm.js.LICENSE.txt +1 -1
  6. package/dist/audionew.cjs.js.LICENSE.txt +1 -1
  7. package/dist/audionew.esm.js.LICENSE.txt +1 -1
  8. package/dist/base.cjs.js.LICENSE.txt +1 -1
  9. package/dist/base.esm.js.LICENSE.txt +1 -1
  10. package/dist/beta-desktop-bar.cjs.js.LICENSE.txt +1 -1
  11. package/dist/beta-desktop-bar.esm.js.LICENSE.txt +1 -1
  12. package/dist/beta-mobile-bar.cjs.js.LICENSE.txt +1 -1
  13. package/dist/beta-mobile-bar.esm.js.LICENSE.txt +1 -1
  14. package/dist/bundle.umd.js +1 -1
  15. package/dist/bundle.umd.js.LICENSE.txt +1 -1
  16. package/dist/button.cjs.js.LICENSE.txt +1 -1
  17. package/dist/button.esm.js.LICENSE.txt +1 -1
  18. package/dist/card-getter.cjs.js.LICENSE.txt +1 -1
  19. package/dist/card-getter.esm.js.LICENSE.txt +1 -1
  20. package/dist/center.cjs.js.LICENSE.txt +1 -1
  21. package/dist/center.esm.js.LICENSE.txt +1 -1
  22. package/dist/checkbox.cjs.js.LICENSE.txt +1 -1
  23. package/dist/checkbox.esm.js.LICENSE.txt +1 -1
  24. package/dist/code.cjs.js.LICENSE.txt +1 -1
  25. package/dist/code.esm.js.LICENSE.txt +1 -1
  26. package/dist/container.cjs.js.LICENSE.txt +1 -1
  27. package/dist/container.esm.js.LICENSE.txt +1 -1
  28. package/dist/data-list.cjs.js.LICENSE.txt +1 -1
  29. package/dist/data-list.esm.js.LICENSE.txt +1 -1
  30. package/dist/designer.cjs.js +1 -1
  31. package/dist/designer.cjs.js.LICENSE.txt +1 -1
  32. package/dist/designer.esm.js +1 -1
  33. package/dist/designer.esm.js.LICENSE.txt +1 -1
  34. package/dist/element-mapper.cjs.js +1 -1
  35. package/dist/element-mapper.cjs.js.LICENSE.txt +1 -1
  36. package/dist/element-mapper.esm.js +1 -1
  37. package/dist/element-mapper.esm.js.LICENSE.txt +1 -1
  38. package/dist/finalresult.esm.js +1 -1
  39. package/dist/finalresult.esm.js.LICENSE.txt +1 -1
  40. package/dist/flex-card.cjs.js.LICENSE.txt +1 -1
  41. package/dist/flex-card.esm.js.LICENSE.txt +1 -1
  42. package/dist/flex-grid.cjs.js.LICENSE.txt +1 -1
  43. package/dist/flex-grid.esm.js.LICENSE.txt +1 -1
  44. package/dist/flex-row.cjs.js.LICENSE.txt +1 -1
  45. package/dist/flex-row.esm.js.LICENSE.txt +1 -1
  46. package/dist/floating-input.cjs.js.LICENSE.txt +1 -1
  47. package/dist/floating-input.esm.js.LICENSE.txt +1 -1
  48. package/dist/free.cjs.js.LICENSE.txt +1 -1
  49. package/dist/free.esm.js.LICENSE.txt +1 -1
  50. package/dist/horizontal-scroller.cjs.js.LICENSE.txt +1 -1
  51. package/dist/horizontal-scroller.esm.js.LICENSE.txt +1 -1
  52. package/dist/image-picker.cjs.js.LICENSE.txt +1 -1
  53. package/dist/image-picker.esm.js.LICENSE.txt +1 -1
  54. package/dist/image.cjs.js.LICENSE.txt +1 -1
  55. package/dist/image.esm.js.LICENSE.txt +1 -1
  56. package/dist/index.cjs.js +1 -1
  57. package/dist/index.cjs.js.LICENSE.txt +1 -1
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.esm.js +1 -1
  60. package/dist/index.esm.js.LICENSE.txt +1 -1
  61. package/dist/keyframe-animation.cjs.js.LICENSE.txt +1 -1
  62. package/dist/keyframe-animation.esm.js.LICENSE.txt +1 -1
  63. package/dist/link-getter.cjs.js +1 -1
  64. package/dist/link-getter.cjs.js.LICENSE.txt +1 -1
  65. package/dist/link-getter.esm.js +1 -1
  66. package/dist/link-getter.esm.js.LICENSE.txt +1 -1
  67. package/dist/link.cjs.js +1 -1
  68. package/dist/link.cjs.js.LICENSE.txt +1 -1
  69. package/dist/link.esm.js +1 -1
  70. package/dist/link.esm.js.LICENSE.txt +1 -1
  71. package/dist/meta-adder.cjs.js.LICENSE.txt +1 -1
  72. package/dist/meta-adder.esm.js.LICENSE.txt +1 -1
  73. package/dist/modal-2025.cjs.js.LICENSE.txt +1 -1
  74. package/dist/modal-2025.esm.js.LICENSE.txt +1 -1
  75. package/dist/multiswitcher.cjs.js.LICENSE.txt +1 -1
  76. package/dist/multiswitcher.esm.js.LICENSE.txt +1 -1
  77. package/dist/new-nav-bar.cjs.js.LICENSE.txt +1 -1
  78. package/dist/new-nav-bar.esm.js.LICENSE.txt +1 -1
  79. package/dist/picker.cjs.js.LICENSE.txt +1 -1
  80. package/dist/picker.esm.js.LICENSE.txt +1 -1
  81. package/dist/progress.cjs.js.LICENSE.txt +1 -1
  82. package/dist/progress.esm.js.LICENSE.txt +1 -1
  83. package/dist/radio.cjs.js.LICENSE.txt +1 -1
  84. package/dist/radio.esm.js.LICENSE.txt +1 -1
  85. package/dist/range.cjs.js.LICENSE.txt +1 -1
  86. package/dist/range.esm.js.LICENSE.txt +1 -1
  87. package/dist/scroll-video.cjs.js.LICENSE.txt +1 -1
  88. package/dist/scroll-video.esm.js.LICENSE.txt +1 -1
  89. package/dist/side-bar.cjs.js.LICENSE.txt +1 -1
  90. package/dist/side-bar.esm.js.LICENSE.txt +1 -1
  91. package/dist/side-nav-bar.cjs.js.LICENSE.txt +1 -1
  92. package/dist/side-nav-bar.esm.js.LICENSE.txt +1 -1
  93. package/dist/simple-bar.cjs.js.LICENSE.txt +1 -1
  94. package/dist/simple-bar.esm.js.LICENSE.txt +1 -1
  95. package/dist/slider-2025.cjs.js.LICENSE.txt +1 -1
  96. package/dist/slider-2025.esm.js.LICENSE.txt +1 -1
  97. package/dist/spacer.cjs.js.LICENSE.txt +1 -1
  98. package/dist/spacer.esm.js.LICENSE.txt +1 -1
  99. package/dist/stack.cjs.js.LICENSE.txt +1 -1
  100. package/dist/stack.esm.js.LICENSE.txt +1 -1
  101. package/dist/stacker.cjs.js.LICENSE.txt +1 -1
  102. package/dist/stacker.esm.js.LICENSE.txt +1 -1
  103. package/dist/table.cjs.js.LICENSE.txt +1 -1
  104. package/dist/table.esm.js.LICENSE.txt +1 -1
  105. package/dist/text-field.cjs.js +1 -1
  106. package/dist/text-field.cjs.js.LICENSE.txt +1 -1
  107. package/dist/text-field.esm.js +1 -1
  108. package/dist/text-field.esm.js.LICENSE.txt +1 -1
  109. package/dist/text.cjs.js.LICENSE.txt +1 -1
  110. package/dist/text.esm.js.LICENSE.txt +1 -1
  111. package/dist/theme.cjs.js.LICENSE.txt +1 -1
  112. package/dist/theme.esm.js.LICENSE.txt +1 -1
  113. package/dist/transform-anim.cjs.js.LICENSE.txt +1 -1
  114. package/dist/transform-anim.esm.js.LICENSE.txt +1 -1
  115. package/dist/ulist.cjs.js.LICENSE.txt +1 -1
  116. package/dist/ulist.esm.js.LICENSE.txt +1 -1
  117. package/dist/video.cjs.js.LICENSE.txt +1 -1
  118. package/dist/video.esm.js.LICENSE.txt +1 -1
  119. package/dist/wrap.cjs.js.LICENSE.txt +1 -1
  120. package/dist/wrap.esm.js.LICENSE.txt +1 -1
  121. package/dist/zoom-card.cjs.js.LICENSE.txt +1 -1
  122. package/dist/zoom-card.esm.js.LICENSE.txt +1 -1
  123. package/layout/animator.js +1 -1
  124. package/layout/audio.js +1 -1
  125. package/layout/audionew.js +1 -1
  126. package/layout/base.js +1 -1
  127. package/layout/beta-desktop-bar.js +1 -1
  128. package/layout/beta-mobile-bar.js +1 -1
  129. package/layout/button.js +1 -1
  130. package/layout/center.js +1 -1
  131. package/layout/checkbox.js +1 -1
  132. package/layout/circle.js +1 -1
  133. package/layout/code.js +1 -1
  134. package/layout/container.js +1 -1
  135. package/layout/dropdown-2025.js +1 -1
  136. package/layout/flex-card.js +1 -1
  137. package/layout/flex-grid.js +1 -1
  138. package/layout/flex-row.js +1 -1
  139. package/layout/form-components/custom.js +1 -1
  140. package/layout/form-components/data-list.js +1 -1
  141. package/layout/form-components/floating-input.js +1 -1
  142. package/layout/form-components/form-all.js +1 -1
  143. package/layout/form-components/form.js +9 -2
  144. package/layout/form-components/image-picker.js +1 -1
  145. package/layout/form-components/picker.js +1 -1
  146. package/layout/form-components/radio.js +1 -1
  147. package/layout/form-components/radiogroup.js +1 -1
  148. package/layout/form-components/range.js +1 -1
  149. package/layout/free.js +1 -1
  150. package/layout/grid-overlay.js +1 -1
  151. package/layout/grid-switcher.js +1 -1
  152. package/layout/grid.js +1 -1
  153. package/layout/horizontal-scroller.js +1 -1
  154. package/layout/image.js +1 -1
  155. package/layout/index.js +1 -1
  156. package/layout/link.js +6 -3
  157. package/layout/list.js +1 -1
  158. package/layout/meta-adder.js +1 -1
  159. package/layout/modal-2025.js +1 -1
  160. package/layout/morph.js +1 -1
  161. package/layout/multiswitcher.js +1 -1
  162. package/layout/nav-bar.js +1 -1
  163. package/layout/nav-factor/custom-div.js +1 -1
  164. package/layout/new-nav-bar.js +1 -1
  165. package/layout/polygon.js +1 -1
  166. package/layout/prerender-site.js +1 -1
  167. package/layout/prerender.js +1 -1
  168. package/layout/progress.js +1 -1
  169. package/layout/row.js +1 -1
  170. package/layout/scroll-video.js +1 -1
  171. package/layout/shop.js +1 -1
  172. package/layout/side-bar.js +1 -1
  173. package/layout/side-nav-bar.js +1 -1
  174. package/layout/simple-bar.js +1 -1
  175. package/layout/slider-2025.js +1 -1
  176. package/layout/spacer.js +1 -1
  177. package/layout/stack.js +1 -1
  178. package/layout/svg.js +1 -1
  179. package/layout/switcher.js +1 -1
  180. package/layout/table.js +1 -1
  181. package/layout/text-field.js +4 -2
  182. package/layout/text.js +1 -1
  183. package/layout/ulist.js +1 -1
  184. package/layout/video.js +1 -1
  185. package/layout/wrap.js +1 -1
  186. package/layout/zoom-card.js +1 -1
  187. package/lib/agent-surface.js +1 -1
  188. package/lib/card-getter.js +1 -1
  189. package/lib/check-page.js +37 -5
  190. package/lib/codegen.js +1 -1
  191. package/lib/data.js +1 -1
  192. package/lib/designer.js +1 -1
  193. package/lib/element-mapper.js +3 -1
  194. package/lib/element-params.generated.js +3 -3
  195. package/lib/grid-geometry.js +1 -1
  196. package/lib/keyframe-animation.js +1 -1
  197. package/lib/known-inert.js +85 -0
  198. package/lib/link-getter.js +1 -1
  199. package/lib/morph-node.js +1 -1
  200. package/lib/normalize-spec.js +1 -1
  201. package/lib/parse-html.js +1 -1
  202. package/lib/raster-inspect.js +1 -1
  203. package/lib/raster-ops.js +1 -1
  204. package/lib/raster-presets.js +1 -1
  205. package/lib/resolve-refs.js +1 -1
  206. package/lib/scroll-video.js +1 -1
  207. package/lib/seo.js +1 -1
  208. package/lib/stacker.js +1 -1
  209. package/lib/suggest.js +1 -1
  210. package/lib/theme.js +1 -1
  211. package/lib/transform-anim.js +1 -1
  212. package/lib/transition.js +1 -1
  213. package/lib/validate-nodes.js +14 -1
  214. package/lib/webmcp-adapter.js +1 -1
  215. package/package.json +1 -1
  216. package/schema.json +2620 -957
  217. package/scripts/generate-schema.mjs +7 -0
  218. package/skills/nodality/SKILL.md +11 -1
package/layout/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/link.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -362,8 +362,11 @@ obj.pad && (stra += `\n pad: ${rempad},`);
362
362
  obj.color && this.color(obj.color);
363
363
 
364
364
 
365
- //@ rounded: Apply the default corner radius. Use `radius` for a specific value.
366
- obj.rounded && this.round();
365
+ //@ rounded: Apply the default corner radius (0.5rem). Use `radius` for a specific value.
366
+ // It called the deprecated round() with no value, which set
367
+ // border-radius to undefined: no rounding, and a deprecation error in
368
+ // the console of every page that used it.
369
+ obj.rounded && this.radius("0.5rem");
367
370
 
368
371
  //@ new: Open in a new tab — sets target="_blank" and rel="noopener noreferrer".
369
372
  if (obj.new){
package/layout/list.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/morph.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/nav-bar.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/polygon.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/row.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/shop.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/spacer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/stack.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/svg.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/table.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -79,7 +79,9 @@ class TextField extends Animator {
79
79
  //@ exact: Font size as an exact CSS length, e.g. "0.875rem".
80
80
  obj.exact && (this.res.style.fontSize = obj.exact);
81
81
  //@ radius: Corner radius in pixels. A bare number, not a CSS length.
82
- obj.radius && this.round(obj.radius);
82
+ // radius(), not the deprecated round(): the library's own component
83
+ // was the source of the deprecation error on every page with a field.
84
+ obj.radius && this.radius(obj.radius);
83
85
  obj.color && (this.res.style.color = obj.color);
84
86
  obj.background && (this.res.style.background = obj.background);
85
87
  obj.font && (this.res.style.fontFamily = obj.font);
package/layout/text.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/ulist.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/video.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/layout/wrap.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/check-page.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -223,14 +223,29 @@ const IN_PAGE = () => {
223
223
  });
224
224
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
225
225
  };
226
- const bgOf = (el) => {
226
+ const bgColour = (el) => {
227
227
  for (let n = el; n && n !== document.documentElement; n = n.parentElement) {
228
228
  const cs = getComputedStyle(n);
229
229
  if (cs.backgroundImage && cs.backgroundImage !== "none") return null;
230
- const l = lum(cs.backgroundColor);
231
- if (l !== null) return l;
230
+ if (lum(cs.backgroundColor) !== null) return cs.backgroundColor;
232
231
  }
233
- return lum(getComputedStyle(document.body).backgroundColor);
232
+ const body = getComputedStyle(document.body).backgroundColor;
233
+ return lum(body) !== null ? body : null;
234
+ };
235
+ const bgOf = (el) => { const c = bgColour(el); return c === null ? null : lum(c); };
236
+ // APCA (0.0.98G-4g): perceived contrast, which accounts for polarity and
237
+ // for how mid-tone grounds compress it. WCAG 2 ratios pass thin small text
238
+ // on a mid-tone that people find hard to read — 11:1 on a turquoise that
239
+ // APCA put at Lc 72 for 13.8px mono. Reported alongside, not instead.
240
+ const apca = (fgc, bgc) => {
241
+ const rgb = (c) => c.match(/[\d.]+/g).slice(0, 3).map(Number);
242
+ const Y = ([r, g, b]) => {
243
+ let y = 0.2126729 * (r / 255) ** 2.4 + 0.7151522 * (g / 255) ** 2.4 + 0.0721750 * (b / 255) ** 2.4;
244
+ return y < 0.022 ? y + (0.022 - y) ** 1.414 : y;
245
+ };
246
+ const t = Y(rgb(fgc)), b = Y(rgb(bgc));
247
+ if (b > t) { const v = (b ** 0.56 - t ** 0.57) * 1.14; return v < 0.1 ? 0 : (v - 0.027) * 100; }
248
+ const v = (b ** 0.65 - t ** 0.62) * 1.14; return v > -0.1 ? 0 : -(v + 0.027) * 100;
234
249
  };
235
250
  for (const el of all) {
236
251
  const own = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());
@@ -246,6 +261,17 @@ const IN_PAGE = () => {
246
261
  if (ratio < need) {
247
262
  add("LOW_CONTRAST", el, `${ratio.toFixed(2)}:1`,
248
263
  `needs ${need}:1 at ${Math.round(size)}px`);
264
+ } else if (size < 24) {
265
+ // Passes WCAG, may still read faint. Lc 75 is APCA's floor for
266
+ // body text, 60 for larger content text; heavier type is allowed
267
+ // a little less.
268
+ const lc = Math.abs(apca(cs.color, bgColour(el)));
269
+ const heavy = Number(cs.fontWeight) >= 600;
270
+ const floor = (size < 16 ? 75 : 60) - (heavy ? 10 : 0);
271
+ if (lc < floor) {
272
+ add("FAINT_TEXT", el, `APCA Lc ${Math.round(lc)}`,
273
+ `passes WCAG (${ratio.toFixed(1)}:1) but reads faint at ${Math.round(size)}px weight ${cs.fontWeight}; aim for Lc ${floor}+`);
274
+ }
249
275
  }
250
276
  }
251
277
  return out;
@@ -290,6 +316,12 @@ const REPAIRS = {
290
316
  `background: "<a background with more separation>"`],
291
317
  valid: ["4.5:1 for body text, 3:1 at 24px or at 18.66px bold"],
292
318
  },
319
+ FAINT_TEXT: {
320
+ suggestions: [`keySet: [{ key: "fontWeight", value: "500" }]`,
321
+ `a lighter background tint, or text closer to black/white`,
322
+ `a larger size`],
323
+ valid: ["APCA Lc 75+ under 16px, 60+ up to 24px (10 less at weight 600+). A mid-tone ground caps the contrast any text can reach."],
324
+ },
293
325
  HEADING_LEVEL_SKIPPED: {
294
326
  suggestions: [`tag: "h<the next level down>"`],
295
327
  valid: ["`tag` sets the heading level independently of the size scale, " +
package/lib/codegen.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/data.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
package/lib/designer.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * nodality v1.3.15
2
+ * nodality v1.3.16
3
3
  * (c) 2026 Filip Vabrousek
4
4
  * License: MIT
5
5
  */
@@ -2433,6 +2433,8 @@ static form(obj){
2433
2433
  action: el.action ?? "",
2434
2434
  ...(el.method !== undefined ? { method: el.method } : {}),
2435
2435
  ...(el.id !== undefined ? { id: el.id } : {}),
2436
+ //@ form.title {text}: What the form is for, in a sentence. Its accessible name, and the description of the tool the agent surface derives from it.
2437
+ ...(el.title !== undefined ? { title: el.title } : {}),
2436
2438
  });
2437
2439
  const kids = Array.isArray(el.children) ? el.children : null;
2438
2440
  if (kids) form.add(kids.map((child) => this.mapType({ ...obj, el: child })));